1(*
2This Source Code Form is subject to the terms of the Mozilla Public
3License, v. 2.0. If a copy of the MPL was not distributed with this
4file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
6Copyright (c) Alexey Torgashin
7*)
8{$ifdef nn}begin end;{$endif}
9
10procedure TfmMain.DoLoadCommandLineBaseOptions(out AWindowPos: string;
11  out AAllowSessionLoad, AAllowSessionSave: TAppAllowSomething;
12  out AFileFolderCount: integer);
13// Function handles these options: -v -h -w -el -ns
14// Option -n is handled via var proc_globdata.AppAlwaysNewInstance
15var
16  SParam: string;
17  i: integer;
18begin
19  AWindowPos:= '';
20  AAllowSessionLoad:= aalsEnable;
21  AAllowSessionSave:= aalsEnable;
22  AFileFolderCount:= 0;
23
24  for i:= 1 to ParamCount do
25  begin
26    SParam:= ParamStr(i);
27    if not SBeginsWith(SParam, '-') then
28    begin
29      if AAllowSessionLoad=aalsEnable then
30        AAllowSessionLoad:= aalsNotGood; //block loading last session if any filenames present
31      Inc(AFileFolderCount);
32      Continue;
33    end;
34
35    if (SParam='--version') or (SParam='-v') then
36    begin
37      MsgStdout('CudaText '+cAppExeVersion, true);
38      Halt;
39    end;
40
41    if (SParam='--help') or (SParam='-h') then
42    begin
43      MsgStdout(msgCommandLineHelp, true);
44      Halt;
45    end;
46
47    if SBeginsWith(SParam, '-w=') then
48    begin
49      AWindowPos:= Copy(SParam, 4, MaxInt);
50      Continue;
51    end;
52
53    if (SParam='-el') then
54    begin
55      MsgStdout(AppEncodingListAsString, true);
56      Halt;
57    end;
58
59    if (SParam='-ns') then
60    begin
61      AAllowSessionLoad:= aalsDisable;
62      AAllowSessionSave:= aalsDisable;
63      Continue;
64    end;
65
66    if (SParam='-nsl') then
67    begin
68      AAllowSessionLoad:= aalsDisable;
69      Continue;
70    end;
71
72    if (SParam='-nss') then
73    begin
74      AAllowSessionSave:= aalsDisable;
75      Continue;
76    end;
77  end;
78end;
79
80
81function _GetStdin: string;
82var
83  s: string;
84begin
85  Result:= '';
86  Reset(Input);
87  while not EOF(Input) do
88  begin
89    ReadLn(Input, s);
90    Result+= s+#10;
91  end;
92end;
93
94procedure _AppFindFilesByMask(List: TStringList; AMask: string);
95var
96  Dir: string;
97begin
98  Dir:= GetCurrentDirUTF8;
99
100  //support full dir path
101  if IsOsFullPath(AMask) then
102  begin
103    Dir:= ExtractFileDir(AMask);
104    AMask:= ExtractFileName(AMask);
105  end
106  else
107  //support relative dir path
108  if Pos(DirectorySeparator, AMask)>0 then
109  begin
110    Dir+= DirectorySeparator+ExtractFileDir(AMask);
111    AMask:= ExtractFileName(AMask);
112  end;
113
114  FindAllFiles(List, Dir, AMask, false{SubDirs});
115end;
116
117procedure TfmMain.DoLoadCommandParams(const AParams: array of string; AOpenOptions: string);
118// Function handles passed file names, folder names, and such params as -r -nh -z -e,
119// while others params are handled in DoLoadCommandLineBaseOptions
120var
121  Frame: TEditorFrame;
122  SParam: string;
123  CliModule: string;
124  CliParams: TAppStringArray;
125  NLine, NColumn, i: integer;
126  bReadOnly: boolean;
127  bAllowCreate: boolean;
128  sEncoding, sCli: string;
129  SepCli: TATStringSeparator;
130  List: TStringList;
131begin
132  bReadOnly:= false;
133  bAllowCreate:= true;
134  sEncoding:= '';
135
136  for i:= 0 to Length(AParams)-1 do
137  begin
138    SParam:= AParams[i];
139    if SParam='' then
140      Continue;
141
142    //remove " quotes, CudaText issue #3726
143    SParam:= SParam.DeQuotedString('"');
144
145    if SParam='-r' then
146    begin
147      bReadOnly:= true;
148      Continue;
149    end;
150
151    if SParam='-nh' then
152    begin
153      AOpenOptions+= '/nohistory';
154      Continue;
155    end;
156
157    if SParam='-nn' then
158    begin
159      bAllowCreate:= false;
160      Continue;
161    end;
162
163    if SBeginsWith(SParam, '-z=') then
164    begin
165      // '-z=text' must give '/view-text'
166      AOpenOptions+= '/view-'+Copy(SParam, 4, MaxInt);
167      Continue;
168    end;
169
170    if SBeginsWith(SParam, '-e=') then
171    begin
172      sEncoding:= AppEncodingShortnameToFullname( Copy(SParam, 4, MaxInt) );
173      Continue;
174    end;
175
176    if SBeginsWith(SParam, '-p=') then
177    begin
178      SepCli.Init(Copy(SParam, 4, MaxInt), '#');
179      SepCli.GetItemStr(CliModule);
180      SetLength(CliParams, 0);
181      while SepCli.GetItemStr(sCli) do
182      begin
183        SetLength(CliParams, Length(CliParams)+1);
184        CliParams[High(CliParams)]:= sCli;
185      end;
186      DoApplyCli(CliModule, CliParams);
187      Continue;
188    end;
189
190    {$ifdef unix}
191    if SParam='-i' then
192    begin
193      Frame:= Frames[0];
194      if not Frame.IsEmpty then
195        Frame:= DoFileOpen('', '', nil, '/nohistory');
196      if Assigned(Frame) then
197      begin
198        Frame.TabCaption:= '(stdin)';
199        Frame.Ed1.Strings.LoadFromString(_GetStdin);
200        //Frame.Ed1.Modified:= false;
201      end;
202      Continue;
203    end;
204    {$endif}
205
206    (*
207    {$ifdef darwin}
208    //macOS gives param -psn** for debugger
209    if SBeginsWith(SParam, '-psn') then
210      Continue;
211    {$endif}
212    *)
213
214    //skip all other keys, to not see them as filenames
215    if SBeginsWith(SParam, '-') then
216      Continue;
217
218    SParam:= AppExpandFilename(SParam);
219
220    //here we assume that SParam is filename/dirname/filemask
221    if not IsOsFullPath(SParam) then
222      SParam:= GetCurrentDirUTF8+DirectorySeparator+SParam;
223
224    SParseFilenameWithTwoNumbers(SParam, NLine, NColumn);
225
226    //if folder, open it in ProjManager
227    if DirectoryExistsUTF8(SParam) then
228    begin
229      DoFolderOpen(SParam, False, cInvokeAppInternal);
230    end
231    else
232    if FileExists(SParam) then
233    begin
234      Frame:= DoFileOpen(SParam, '', nil, AOpenOptions);
235      if Assigned(Frame) then
236      begin
237        if sEncoding<>'' then
238          SetFrameEncoding(Frame.Ed1, sEncoding, true);
239
240        if (NLine>0) then
241          Frame.DoGotoPos(Frame.Ed1, NColumn-1, NLine-1);
242
243        if bReadOnly then
244          Frame.ReadOnly[Frame.Ed1]:= true;
245      end;
246    end
247    else
248    //file mask with '*' char?
249    if Pos('*', SParam)>0 then
250    begin
251      List:= TStringList.Create;
252      try
253        _AppFindFilesByMask(List, SParam);
254        for SParam in List do
255        begin
256          Frame:= DoFileOpen(SParam, '', nil, AOpenOptions);
257          if Assigned(Frame) then
258          begin
259            if sEncoding<>'' then
260              SetFrameEncoding(Frame.Ed1, sEncoding, true);
261
262            if bReadOnly then
263              Frame.ReadOnly[Frame.Ed1]:= true;
264          end;
265        end;
266      finally
267        FreeAndNil(List);
268      end;
269    end
270    else
271    //file not exists? suggest to create it
272    if bAllowCreate and AppFileExtentionCreatable(SParam) then
273      if MsgBox(Format(msgConfirmCreateNewFile, [SParam]),
274              MB_OKCANCEL or MB_ICONQUESTION) = ID_OK then
275        if AppCreateFile(SParam) then
276        begin
277          Frame:= DoFileOpen(SParam, '', nil, AOpenOptions);
278          if Assigned(Frame) then
279          begin
280            if sEncoding<>'' then
281              SetFrameEncoding(Frame.Ed1, sEncoding, true);
282          end;
283        end;
284  end;
285
286  //if session file was opened, we must update caption
287  UpdateCaption;
288end;
289
290
291{$ifdef windows}
292procedure TfmMain.SecondInstance(const Msg: TBytes);
293var
294  Sep: TATStringSeparator;
295  Params: array of string;
296  S: string;
297begin
298  if not IsAllowedToOpenFileNow then Exit;
299
300  SetLength(Params, 0);
301  S:= '';
302
303  Sep.Init(UTF8Encode(TEncoding.UTF8.GetString(Msg)), '|');
304  while Sep.GetItemStr(S) do
305  begin
306    SetLength(Params, Length(Params)+1);
307    Params[Length(Params)-1]:= S;
308  end;
309
310  DoLoadCommandParams(Params, '');
311
312  if WindowState = wsMinimized then
313  begin
314    Application.Restore;
315    Application.ProcessMessages;
316  end;
317end;
318{$endif}
319
320
321procedure TfmMain.UniqInstanceOtherInstance(Sender: TObject;
322  ParamCount: Integer; const Parameters: array of String);
323begin
324  if not IsAllowedToOpenFileNow then exit;
325
326  DoLoadCommandParams(Parameters, '');
327
328  if WindowState=wsMinimized then
329  begin
330    Application.Restore;
331    Application.ProcessMessages;
332  end;
333
334  {$ifdef windows}
335  // Those two calls below conflicts with Windows SwitchToThisWindow API call
336  // so they are left for other platforms
337  {$else}
338  Application.BringToFront;
339  DoFocusWindow(Handle);
340  {$ifend}
341end;
342
343procedure TfmMain.DoLoadCommandLine;
344const
345  cOptionPassive = '/passive /nonear';
346  cOptionActive = '/nonear';
347var
348  Params: array of string;
349  Options: string;
350  i: integer;
351begin
352  DoLoadCommandParams(FFileNamesDroppedInitially, cOptionPassive);
353
354  //if passed single file, must activate it, else not
355  if ParamCount<2 then
356    Options:= cOptionActive
357  else
358    Options:= cOptionPassive;
359
360  SetLength(Params, ParamCount);
361  for i:= 1 to Length(Params) do
362    Params[i-1]:= ParamStrUTF8(i);
363
364  DoLoadCommandParams(Params, Options);
365end;
366
367procedure TfmMain.DoLoadCommandLine_FromString(const AText: string);
368var
369  StrArray: TStringArray;
370begin
371  if Trim(AText)='' then exit;
372  StrArray:= AText.Split(' ', '"', '"', TStringSplitOptions.ExcludeEmpty);
373  DoLoadCommandParams(StrArray, '');
374end;
375
376