add read only support for dub SDL projects, close #96

This commit is contained in:
Basile Burg 2016-09-02 14:41:22 +02:00
parent dfd7bbf633
commit 1cf1c8b287
No known key found for this signature in database
GPG Key ID: 1868039F415CB8CF
6 changed files with 173 additions and 67 deletions

View File

@ -13,14 +13,19 @@ enum ErrorType: ubyte
error error
} }
/// Stores a dparse AST error
@NoInit @NoGc struct AstError @NoInit @NoGc struct AstError
{ {
///
ErrorType type; ErrorType type;
///
@NoGc string message; @NoGc string message;
///
size_t line, column; size_t line, column;
@disable this(); @disable this();
///
this(ErrorType type, string message, size_t line, size_t column) @nogc @safe this(ErrorType type, string message, size_t line, size_t column) @nogc @safe
{ {
this.type = type; this.type = type;
@ -43,6 +48,7 @@ alias AstErrors = AstError*[];
destruct(err); destruct(err);
} }
/// Write function call when compiled with version "devel"
enum logCall = enum logCall =
q{ q{
import std.experimental.logger: log; import std.experimental.logger: log;
@ -162,13 +168,12 @@ private static immutable predefinedVersions = [
"X86_64" "X86_64"
]; ];
private void fillBadVersions() private void fillBadVrsions()
{ {
// note: compiler switch -m32/64 can lead to wrong results // note: compiler switch -m32/64 can lead to wrong results
string addVersionidentifier(string ver)()
{ alias addVerId = (ver) => `version(` ~ ver ~ `){}
return `version(` ~ ver ~ `){} else _badVersions["` ~ ver ~ "\"] = true;\n"; else _badVersions["` ~ ver ~ "\"] = true;\n";
}
string addVerionIdentifiers() string addVerionIdentifiers()
{ {
@ -177,7 +182,7 @@ private void fillBadVersions()
string result; string result;
foreach(i; aliasSeqOf!(iota(0, predefinedVersions.length))) foreach(i; aliasSeqOf!(iota(0, predefinedVersions.length)))
{ {
result ~= addVersionidentifier!(predefinedVersions[i]); result ~= addVerId(predefinedVersions[i]);
} }
return result; return result;
} }
@ -358,8 +363,7 @@ T parseAndVisit(T : ASTVisitor)(const(char)[] source)
* By default libdparse outputs errors and warnings to the standard streams. * By default libdparse outputs errors and warnings to the standard streams.
* This function prevents that. * This function prevents that.
*/ */
void ignoreErrors(string fname, size_t line, size_t col, string message, void ignoreErrors(string, size_t, size_t, string, bool)
bool err)
{ {
// dont pollute output // dont pollute output
} }

View File

@ -54,6 +54,7 @@ type
TCEDubProject = class(TComponent, ICECommonProject) TCEDubProject = class(TComponent, ICECommonProject)
private private
fIsSdl: boolean;
fInGroup: boolean; fInGroup: boolean;
fDubProc: TCEProcess; fDubProc: TCEProcess;
fPreCompilePath: string; fPreCompilePath: string;
@ -130,6 +131,7 @@ type
// //
property json: TJSONObject read fJSON; property json: TJSONObject read fJSON;
property packageName: string read fPackageName; property packageName: string read fPackageName;
property isSDL: boolean read fIsSdl;
end; end;
// these 9 built types always exist // these 9 built types always exist
@ -138,6 +140,9 @@ type
// returns true if filename is a valid dub project. Only json format is supported. // returns true if filename is a valid dub project. Only json format is supported.
function isValidDubProject(const filename: string): boolean; function isValidDubProject(const filename: string): boolean;
// converts a sdl description to json, returns the json
function sdl2json(const filename: string): TJSONObject;
function getDubCompiler: TCECompiler; function getDubCompiler: TCECompiler;
procedure setDubCompiler(value: TCECompiler); procedure setDubCompiler(value: TCECompiler);
@ -145,6 +150,9 @@ var
DubCompiler: TCECompiler = dmd; DubCompiler: TCECompiler = dmd;
DubCompilerFilename: string = 'dmd'; DubCompilerFilename: string = 'dmd';
const
DubSdlWarning = 'this feature is not available for a DUB project with the SDL format';
implementation implementation
var var
@ -330,66 +338,83 @@ procedure TCEDubProject.loadFromFile(const fname: string);
var var
loader: TMemoryStream; loader: TMemoryStream;
parser : TJSONParser; parser : TJSONParser;
ext: string;
bom: dword = 0; bom: dword = 0;
begin begin
loader := TMemoryStream.Create; ext := fname.extractFileExt.upperCase;
try fBasePath := fname.extractFilePath;
fBasePath := fname.extractFilePath; fFilename := fname;
fFilename := fname; fSaveAsUtf8 := false;
loader.LoadFromFile(fFilename); fIsSdl := false;
fSaveAsUtf8 := false; if ext = '.JSON' then
// skip BOM, this crashes the parser begin
loader.Read(bom, 4); loader := TMemoryStream.Create;
if (bom and $BFBBEF) = $BFBBEF then
begin
loader.Position:= 3;
fSaveAsUtf8 := true;
end
else if (bom = $FFFE0000) or (bom = $FEFF) then
begin
// UCS-4 LE/BE not handled by DUB
loader.clear;
loader.WriteByte(byte('{'));
loader.WriteByte(byte('}'));
loader.Position:= 0;
fFilename := '';
end
else if ((bom and $FEFF) = $FEFF) or ((bom and $FFFE) = $FFFE) then
begin
// UCS-2 LE/BE not handled by DUB
loader.clear;
loader.WriteByte(byte('{'));
loader.WriteByte(byte('}'));
loader.Position:= 0;
fFilename := '';
end
else
loader.Position:= 0;
//
FreeAndNil(fJSON);
parser := TJSONParser.Create(loader, [joIgnoreTrailingComma, joUTF8]);
//TODO-cfcl-json: remove etc/fcl-json the day they'll merge and rlz the version with 'Options'
//TODO-cfcl-json: track possible changes and fixes at http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/fcl-json/
//latest in etc = rev 34196.
try try
try loader.LoadFromFile(fFilename);
fJSON := parser.Parse as TJSONObject; // skip BOMs, they crash the parser
except loader.Read(bom, 4);
if assigned(fJSON) then if (bom and $BFBBEF) = $BFBBEF then
FreeAndNil(fJSON); begin
loader.Position:= 3;
fSaveAsUtf8 := true;
end
else if (bom = $FFFE0000) or (bom = $FEFF) then
begin
// UCS-4 LE/BE not handled by DUB
loader.clear;
loader.WriteByte(byte('{'));
loader.WriteByte(byte('}'));
loader.Position:= 0;
fFilename := ''; fFilename := '';
end
else if ((bom and $FEFF) = $FEFF) or ((bom and $FFFE) = $FFFE) then
begin
// UCS-2 LE/BE not handled by DUB
loader.clear;
loader.WriteByte(byte('{'));
loader.WriteByte(byte('}'));
loader.Position:= 0;
fFilename := '';
end
else
loader.Position:= 0;
//
FreeAndNil(fJSON);
parser := TJSONParser.Create(loader, [joIgnoreTrailingComma, joUTF8]);
//TODO-cfcl-json: remove etc/fcl-json the day they'll merge and rlz the version with 'Options'
//TODO-cfcl-json: track possible changes and fixes at http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/fcl-json/
//latest in etc = rev 34196.
try
try
fJSON := parser.Parse as TJSONObject;
except
if assigned(fJSON) then
FreeAndNil(fJSON);
fFilename := '';
end;
finally
parser.Free;
end; end;
finally finally
parser.Free; loader.Free;
end; end;
finally end
loader.Free; else if ext = '.SDL' then
if not assigned(fJSON) then begin
fJson := TJSONObject.Create(['name','invalid json']); FreeAndNil(fJSON);
updateFields; fJSON := sdl2json(fFilename);
subjProjChanged(fProjectSubject, self); if fJSON.isNil then
fModified := false; fFilename := ''
else
fIsSdl := true;
end; end;
if not assigned(fJSON) then
fJson := TJSONObject.Create(['name','invalid json']);
updateFields;
subjProjChanged(fProjectSubject, self);
fModified := false;
end; end;
procedure TCEDubProject.saveToFile(const fname: string); procedure TCEDubProject.saveToFile(const fname: string);
@ -1073,11 +1098,58 @@ end;
{$ENDREGION --------------------------------------------------------------------} {$ENDREGION --------------------------------------------------------------------}
{$REGION Miscellaneous DUB free functions --------------------------------------} {$REGION Miscellaneous DUB free functions --------------------------------------}
function sdl2json(const filename: string): TJSONObject;
var
dub: TProcess;
str: TStringList;
jsn: TJSONData;
prs: TJSONParser;
old: string;
begin
result := nil;
dub := TProcess.Create(nil);
str := TStringList.Create;
old := GetCurrentDirUTF8;
try
SetCurrentDirUTF8(filename.extractFilePath);
dub.Executable := 'dub' + exeExt;
dub.Options := [poUsePipes{$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
dub.ShowWindow := swoHIDE;
dub.CurrentDirectory:= filename.extractFilePath;
dub.Parameters.Add('describe');
dub.Execute;
processOutputToStrings(dub, str);
while dub.Running do;
prs := TJSONParser.Create(str.Text, [joIgnoreTrailingComma, joUTF8]);
try
jsn := prs.Parse;
try
if jsn.isNotNil and (jsn.JSONType = jtObject)
and TJSONObject(jsn).Find('packages').isNotNil
and (TJSONObject(jsn).Find('packages').JSONType = jtArray)
and (TJSONArray(TJSONObject(jsn).Find('packages')).Count > 0)
and (TJSONArray(TJSONObject(jsn).Find('packages')).Items[0].JSONType = jtObject) then
result := TJSONObject(TJSONArray(TJSONObject(jsn).Find('packages')).Items[0].Clone);
finally
jsn.free;
end;
finally
prs.Free
end;
finally
SetCurrentDirUTF8(old);
dub.free;
str.Free;
end;
end;
function isValidDubProject(const filename: string): boolean; function isValidDubProject(const filename: string): boolean;
var var
maybe: TCEDubProject; maybe: TCEDubProject;
ext: string;
begin begin
if (filename.extractFileExt.upperCase <> '.JSON') then ext := filename.extractFileExt.upperCase;
if (ext <> '.JSON') and (ext <> '.SDL') then
exit(false); exit(false);
result := true; result := true;
// avoid the project to notify the observers, current project is not replaced // avoid the project to notify the observers, current project is not replaced

View File

@ -21,10 +21,10 @@ inherited CEDubProjectEditorWidget: TCEDubProjectEditorWidget
Height = 380 Height = 380
Top = 4 Top = 4
Width = 403 Width = 403
ActivePage = TabSheet2 ActivePage = TabSheet1
Align = alClient Align = alClient
BorderSpacing.Around = 4 BorderSpacing.Around = 4
TabIndex = 1 TabIndex = 0
TabOrder = 0 TabOrder = 0
object TabSheet1: TTabSheet object TabSheet1: TTabSheet
Caption = 'Inspector' Caption = 'Inspector'

View File

@ -287,7 +287,7 @@ begin
if project.getProject <> fProj then if project.getProject <> fProj then
exit; exit;
fProj := nil; fProj := nil;
//
updateEditor; updateEditor;
updateInspector; updateInspector;
enabled := false; enabled := false;
@ -308,6 +308,12 @@ begin
if not Visible then if not Visible then
exit; exit;
if fProj.isSDL then
begin
edProp.Enabled:= false;
btnAcceptProp.Enabled:=false;
end;
updateEditor; updateEditor;
updateInspector; updateInspector;
end; end;

View File

@ -3227,10 +3227,13 @@ begin
end; end;
procedure TCEMainForm.openProj(const fname: string); procedure TCEMainForm.openProj(const fname: string);
var
ext: string;
begin begin
if not closeProj then if not closeProj then
exit; exit;
if fname.extractFileExt.upperCase = '.JSON' then ext := fname.extractFileExt.upperCase;
if (ext = '.JSON') or (ext = '.SDL') then
newDubProj newDubProj
else else
newNativeProj; newNativeProj;
@ -3260,6 +3263,11 @@ procedure TCEMainForm.actProjSaveAsExecute(Sender: TObject);
begin begin
if checkProjectLock then if checkProjectLock then
exit; exit;
if (fProject.getFormat = pfDub) and TCEDubProject(fProject.getProject).isSDL then
begin
fMsgs.message(DubSdlWarning, fProject, amcProj, amkWarn);
exit;
end;
with TSaveDialog.Create(nil) do with TSaveDialog.Create(nil) do
try try
if execute then saveProjAs(filename); if execute then saveProjAs(filename);
@ -3271,6 +3279,11 @@ end;
procedure TCEMainForm.actProjSaveExecute(Sender: TObject); procedure TCEMainForm.actProjSaveExecute(Sender: TObject);
begin begin
if fProject = nil then exit; if fProject = nil then exit;
if (fProject.getFormat = pfDub) and TCEDubProject(fProject.getProject).isSDL then
begin
fMsgs.message(DubSdlWarning, fProject, amcProj, amkWarn);
exit;
end;
if checkProjectLock then if checkProjectLock then
exit; exit;
if fProject.filename.isNotEmpty then saveProj if fProject.filename.isNotEmpty then saveProj
@ -3311,6 +3324,11 @@ procedure TCEMainForm.actProjSourceExecute(Sender: TObject);
begin begin
if fProject = nil then exit; if fProject = nil then exit;
if not fProject.filename.fileExists then exit; if not fProject.filename.fileExists then exit;
if (fProject.getFormat = pfDub) and TCEDubProject(fProject.getProject).isSDL then
begin
fMsgs.message(DubSdlWarning, fProject, amcProj, amkWarn);
exit;
end;
// //
openFile(fProject.filename); openFile(fProject.filename);
fDoc.isProjectDescription := true; fDoc.isProjectDescription := true;

View File

@ -36,17 +36,23 @@ procedure saveModifiedProjectFiles(project: ICECommonProject);
implementation implementation
function isProject(const filename: string): boolean; function isProject(const filename: string): boolean;
var
ext: string;
begin begin
if filename.extractFileExt = '.json' then ext := filename.extractFileExt.upperCase;
if (ext = '.JSON') or (ext = '.SDL') then
result := isValidDubProject(filename) result := isValidDubProject(filename)
else else
result := isValidNativeProject(filename); result := isValidNativeProject(filename);
end; end;
function projectFormat(const filename: string): TCEProjectFileFormat; function projectFormat(const filename: string): TCEProjectFileFormat;
var
ext: string;
begin begin
result := pffNone; result := pffNone;
if filename.extractFileExt = '.json' then ext := filename.extractFileExt.upperCase;
if (ext = '.JSON') or (ext = '.SDL') then
begin begin
if isValidDubProject(filename) then if isValidDubProject(filename) then
result := pffDub; result := pffDub;