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.DoOps_SaveOptionBool(const APath: string; AValue: boolean);
11var
12  cfg: TJSONConfig;
13begin
14  cfg:= TJSONConfig.Create(nil);
15  try
16    try
17      cfg.Formatted:= true; //needs last at__jsonconf.pp
18      cfg.Filename:= AppFile_OptionsUser;
19    except
20      exit;
21    end;
22
23    cfg.SetValue(APath, AValue);
24  finally
25    cfg.Free;
26  end;
27end;
28
29procedure TfmMain.DoOps_SaveOptionString(const APath, AValue: string);
30var
31  cfg: TJSONConfig;
32begin
33  cfg:= TJSONConfig.Create(nil);
34  try
35    try
36      cfg.Formatted:= true; //needs last at__jsonconf.pp
37      cfg.Filename:= AppFile_OptionsUser;
38    except
39      exit;
40    end;
41
42    cfg.SetValue(APath, AValue);
43  finally
44    cfg.Free;
45  end;
46end;
47
48
49procedure TfmMain.DoOps_SaveThemes;
50var
51  cfg: TJSONConfig;
52begin
53  cfg:= TJSONConfig.Create(nil);
54  try
55    try
56      cfg.Formatted:= true;
57      cfg.FileName:= AppFile_OptionsUser;
58    except
59      exit
60    end;
61    cfg.SetValue('/ui_theme', UiOps.ThemeUi);
62    cfg.SetValue('/ui_theme_syntax', UiOps.ThemeSyntax);
63  finally
64    cfg.Free;
65  end;
66end;
67
68procedure TfmMain.DoOps_ClearConfigHistory(AMode: TAppConfigHistoryElements);
69var
70  cfg: TJSONConfig;
71begin
72  cfg:= TJSONConfig.Create(nil);
73  try
74    try
75      cfg.Formatted:= true; //needs last at__jsonconf.pp
76      cfg.Filename:= AppFile_History;
77    except
78      exit;
79    end;
80
81    if acheRecentFiles in AMode then
82    begin
83      cfg.DeleteValue('/recent_files');
84      //
85      AppListRecents.Clear;
86      UpdateMenuRecent(nil);
87      //
88      DeleteFileUTF8(AppFile_HistoryFiles);
89    end;
90
91    if acheSearch in AMode then
92    begin
93      cfg.DeleteValue('/list_find');
94      cfg.DeleteValue('/list_replace');
95      if Assigned(fmFind) then
96      begin
97        fmFind.edFind.Items.Clear;
98        fmFind.edRep.Items.Clear;
99      end;
100    end;
101
102    if acheConsole in AMode then
103    begin
104      cfg.DeleteValue('/list_console');
105      if Assigned(fmConsole) then
106        fmConsole.EdInput.Items.Clear;
107    end;
108  finally
109    cfg.Free;
110  end;
111end;
112
113procedure TfmMain.DoOps_SaveHistory(ASaveModifiedTabs: boolean);
114var
115  cfg: TJSONConfig;
116  bMax: boolean;
117  fnBase: string;
118begin
119  AppDiskCheckFreeSpace(AppFile_History);
120
121  cfg:= TJSONConfig.Create(nil);
122  try
123    try
124      cfg.Formatted:= true; //needs last at__jsonconf.pp
125      cfg.Filename:= AppFile_History;
126    except
127      exit;
128    end;
129
130    ////form
131    if not ShowFullscreen then
132    begin
133      bMax:= WindowState=wsMaximized;
134      cfg.SetValue('/pos/main_max', bMax);
135      if bMax then
136        cfg.SetValue('/pos/main_mon', Monitor.MonitorNum);
137
138      if not IsWindowMaximizedOrFullscreen then
139        cfg.SetValue('/pos/main', FormPosGetAsString(Self, false));
140
141      if AppPanels[cPaneSide].Floating then
142        cfg.SetValue('/pos/side', FormPosGetAsString(AppPanels[cPaneSide].FormFloat, false));
143
144      if AppPanels[cPaneOut].Floating then
145        cfg.SetValue('/pos/bottom', FormPosGetAsString(AppPanels[cPaneOut].FormFloat, false));
146
147      if FloatGroups then
148      begin
149        cfg.SetValue('/pos/g1', FormPosGetAsString(FFormFloatGroups1, false));
150        cfg.SetValue('/pos/g2', FormPosGetAsString(FFormFloatGroups2, false));
151        cfg.SetValue('/pos/g3', FormPosGetAsString(FFormFloatGroups3, false));
152      end;
153
154      cfg.SetValue('show_sidepanel', AppPanels[cPaneSide].Visible);
155      cfg.SetValue('show_bottom', AppPanels[cPaneOut].Visible);
156
157      cfg.SetValue('float_side', AppPanels[cPaneSide].Floating);
158      cfg.SetValue('float_bottom', AppPanels[cPaneOut].Floating);
159
160      with AppPanels[cPaneSide] do
161        if not Floating then
162          cfg.SetValue('size_side', PanelSize);
163
164      with AppPanels[cPaneOut] do
165        if not Floating then
166          cfg.SetValue('size_bottom', PanelSize);
167
168      cfg.SetValue('tab_left', AppPanels[cPaneSide].LastActivePanel);
169    end;
170
171    ////recents
172    cfg.SetValue('/recent_files', AppListRecents);
173
174    ////find dialog
175    if Assigned(fmFind) then
176    begin
177      cfg.SetValue('/list_find', fmFind.edFind.Items);
178      cfg.SetValue('/list_replace', fmFind.edRep.Items);
179      if fmFind.IsNarrow then
180        cfg.SetValue('/pos/find', FormPosGetAsString(fmFind, false));
181      cfg.SetValue('/finder/mline', fmFind.IsMultiLine);
182      cfg.SetValue('/finder/hi', fmFind.IsHiAll);
183      cfg.SetValue('/finder/regex_subst', fmFind.chkRegexSubst.Checked);
184    end;
185
186    if Assigned(fmConsole) then
187      cfg.SetValue('/list_console', fmConsole.EdInput.Items);
188
189    ////finder
190    cfg.SetValue('/finder/regex', FFinder.OptRegex);
191    cfg.SetValue('/finder/case', FFinder.OptCase);
192    cfg.SetValue('/finder/words', FFinder.OptWords);
193    cfg.SetValue('/finder/back', FFinder.OptBack);
194    cfg.SetValue('/finder/confirm', FFinder.OptConfirmReplace);
195    cfg.SetValue('/finder/wrap', FFinder.OptWrapped);
196    cfg.SetValue('/finder/insel', FFinder.OptInSelection);
197    cfg.SetValue('/finder/tokens', Ord(FFinder.OptTokens));
198
199    ////state
200    cfg.SetValue('lang', UiOps.LangName);
201    cfg.SetValue('session', IfThen(UiOps.ReopenSession, ExtractRelativePath(AppFile_OptionsUser, AppSessionName), ''));
202    cfg.SetValue('last_cmd', FLastSelectedCommand);
203
204    DoOps_SaveHistory_GroupView(cfg);
205  finally
206    cfg.Free;
207  end;
208
209  if UiOps.ReopenSession and
210    ((FOption_AllowSessionSave=aalsEnable) or not IsDefaultSessionActive)
211    //// see http://synwrite.sourceforge.net/forums/viewtopic.php?f=20&t=2576
212    //// @tmsg wants to save session always, even with -ns cmdline opt
213  then
214  begin
215    fnBase:= GetSessionFilename;
216    DoOps_SaveSessionsBackups(fnBase);
217    DoOps_SaveSession(fnBase, ASaveModifiedTabs)
218  end;
219end;
220
221
222procedure TfmMain.DoOps_SaveSessionsBackups(const ASessionFilename: string);
223//keep backups of last n unnamed sessions as 'history session.n.cuda-session'
224var
225  fnTemp, fnTemp2: string;
226  i: integer;
227begin
228  for i:= UiOps.BackupLastSessions downto 1 do
229  begin
230    fnTemp:= ChangeFileExt(ASessionFilename, Format('.%d.cuda-session', [i]));
231    if i>1 then
232      fnTemp2:= ChangeFileExt(ASessionFilename, Format('.%d.cuda-session', [i-1]))
233    else
234      fnTemp2:= ASessionFilename;
235    if i>=UiOps.BackupLastSessions then
236      if FileExists(fnTemp) then
237        DeleteFile(fnTemp);
238    if FileExists(fnTemp2) then
239      RenameFile(fnTemp2, fnTemp);
240  end;
241end;
242
243function TfmMain.DoOps_SaveSession(const AFileName: string;
244  ASaveModifiedTabs: boolean): boolean;
245var
246  cfg: TJSONConfig;
247  Frame: TEditorFrame;
248  Gr: TATGroups;
249  Pages: TATPages;
250  nLocalGroup, nGlobalGroup, nTab, i: integer;
251  nCountFiles: integer;
252  path, value: string;
253  bModified: boolean;
254begin
255  Result:= false;
256  if AFileName='' then exit;
257  AppDiskCheckFreeSpace(AFileName);
258  DeleteFile(AFileName);
259
260  nCountFiles:= 0;
261
262  cfg:= TJSONConfig.Create(nil);
263  try
264    try
265      cfg.Formatted:= true;
266      cfg.Filename:= AFileName;
267    except
268      on E: Exception do
269      begin
270        MsgBadConfig(AFileName, E.Message);
271        exit;
272      end;
273    end;
274
275    DoOps_SaveHistory_GroupView(cfg);
276
277    for i:= 0 to cAppMaxGroup do
278    begin
279      Pages:= TGroupsHelper.GetPagesOfGroupIndex(i);
280      if Pages=nil then Continue;
281      cfg.SetValue('/tab_index/g'+IntToStr(i), Pages.Tabs.TabIndex);
282    end;
283    cfg.SetValue('/tab_index/g_active', Groups.FindPages(Groups.PagesCurrent));
284
285    cfg.SetValue('/panels/side_show', AppPanels[cPaneSide].Visible);
286    cfg.SetValue('/panels/side_panel', AppPanels[cPaneSide].LastActivePanel);
287
288    with AppPanels[cPaneSide] do
289      if not Floating then
290        cfg.SetValue('/panels/side_size', PanelSize);
291
292    cfg.SetValue('/panels/bottom_show', AppPanels[cPaneOut].Visible);
293    cfg.SetValue('/panels/bottom_panel', AppPanels[cPaneOut].LastActivePanel);
294
295    with AppPanels[cPaneOut] do
296      if not Floating then
297        cfg.SetValue('/panels/bottom_size', PanelSize);
298
299    for i:= 0 to FrameCount-1 do
300    begin
301      Inc(nCountFiles);
302      Frame:= Frames[i];
303      if Frame.IsEmpty then Continue;
304      if Frame.TabCaption=msgWelcomeTabTitle then Continue; //avoid reopening of '(welcome)' filler text
305
306      if GetAppFilenameIsIgnoredForSession(Frame.FileName) then
307      begin
308        MsgLogConsole(Format('NOTE: File "%s" is not saved to session', [Frame.FileName]));
309        Continue;
310      end;
311
312      path:= '/'+Format('%3.3d', [i]);
313
314      GetFrameLocation(Frame, Gr, Pages, nLocalGroup, nGlobalGroup, nTab);
315      bModified:= Frame.Ed1.Modified or ((Frame.GetFileName(Frame.Ed1)='') and not Frame.IsEmpty);
316
317      cfg.SetValue(path+'/modified', bModified);
318      cfg.SetValue(path+'/file', AppCollapseHomeDirInFilename(Frame.FileName));
319
320      if bModified then
321        cfg.SetValue(path+'/tab_title', Frame.TabCaption);
322      cfg.SetValue(path+'/group', nLocalGroup+1); //support old sessions with 1-based index
323      cfg.SetDeleteValue(path+'/pinned', Frame.TabPinned, false);
324
325      case Frame.FrameKind of
326        efkEditor:
327          value:= '';
328        efkBinaryViewer:
329          value:= 'bin,'+IntToStr(Ord(Frame.Binary.Mode));
330        efkImageViewer:
331          value:= 'pic';
332      end;
333      cfg.SetValue(path+'/kind', value);
334
335      {
336      //TODO: add together with restoring of 'v_pos'
337      if Frame.IsBinary then
338        cfg.SetValue(path+'/v_pos', Frame.Binary.PosOffset)
339      else
340        cfg.DeleteValue(path+'/v_pos');
341        }
342
343      if bModified and ASaveModifiedTabs and UiOps.HistoryItems[ahhText] then
344      begin
345        cfg.SetValue(path+'/text', Frame.Editor.Text);
346        if (Frame.FileName<>'') and FileExists(Frame.FileName) then
347          cfg.SetValue(path+'/file_date', FormatFileDateAsNiceString(Frame.FileName));
348      end;
349
350      Frame.DoSaveHistoryEx(Frame.Ed1, cfg, path, true{AForSession});
351
352      //save info about paired-tab to subkey "pair"
353      if (not Frame.EditorsLinked) and (Frame.FileName2<>'') then
354      begin
355        path+= '/pair';
356
357        bModified:= Frame.Ed2.Modified;
358        cfg.SetValue(path+'/modified', bModified);
359        cfg.SetValue(path+'/file', AppCollapseHomeDirInFilename(Frame.FileName2));
360
361        if UiOps.HistoryItems[ahhText] then
362         if bModified then
363         begin
364          cfg.SetValue(path+'/text', Frame.Ed2.Text);
365          if FileExists(Frame.FileName2) then
366            cfg.SetValue(path+'/file_date', FormatFileDateAsNiceString(Frame.FileName2));
367         end;
368
369        Frame.DoSaveHistoryEx(Frame.Ed2, cfg, path, true{AForSession});
370      end;
371    end;
372
373    Result:= true;
374  finally
375    try
376      cfg.Free; //saves json file
377    except
378      //for incorrect sess folder
379    end;
380  end;
381
382  if UiOps.LogSessions then
383  begin
384    value:= 'Saved session: "'+ExtractFileName(AFileName)+'", '+IntToStr(nCountFiles)+' file(s)';
385    MsgLogConsole(value);
386  end;
387end;
388
389function IsHistorySectionForFilename(const s: string): boolean;
390begin
391  Result:= StrToIntDef(s, -1)>=0;
392end;
393
394function TfmMain.DoOps_LoadSession(const AFileName: string;
395  AllowShowPanels: boolean): boolean;
396var
397  cfg: TJSONConfig;
398  Frame: TEditorFrame;
399  list: TStringlist;
400  sFilename, sFilename2,
401  sTabTitle, sKind, sOpenOptions,
402  item_path, item_path2: string;
403  nCountFiles, nCountFilesModified, nCountFilesBefore: integer;
404  nIndex, i: integer;
405  Pages: TATPages;
406  bModified: boolean;
407  sText: UnicodeString;
408  bExist, bExist2: boolean;
409  sDateSaved, sDateCurrent: string;
410  Params: TAppVariantArray;
411  CurTabs: TATTabs;
412  nTick: QWord;
413const
414  SOptionPassive = '/passive /nonear';
415  SOptionNoHistory = '/nohistory /nolexerdetect /noevent /noopenedevent /nononeevent';
416begin
417  Result:= false;
418  if AFileName='' then exit;
419  if not FileExists(AFileName) then exit;
420
421  //fix issue #3734
422  if not IsDefaultSessionActive then
423  begin
424    sFilename:= GetSessionFilename;
425    if not SameFileName(sFilename, AFileName) then //fix issue #3744
426      DoOps_SaveSession(sFilename, false);
427    sFilename:= '';
428  end;
429
430  DoPyEvent_AppState(APPSTATE_SESSION_LOAD_BEGIN);
431
432  nCountFilesBefore:= FrameCount;
433  if nCountFilesBefore=1 then
434    if Frames[0].IsEmpty then
435      nCountFilesBefore:= 0;
436
437  FSessionIsClosing:= true;
438  try
439    if not DoFileCloseAll(true) then
440    begin
441      DoPyEvent_AppState(APPSTATE_SESSION_LOAD_FAIL);
442      exit;
443    end;
444  finally
445    FSessionIsClosing:= false;
446  end;
447
448  nTick:= GetTickCount64;
449  nCountFiles:= 0;
450  nCountFilesModified:= 0;
451
452  AppFileCheckForNullBytes(AFileName);
453
454  cfg:= TJSONConfig.Create(nil);
455  list:= TStringList.Create;
456  try
457    try
458      cfg.Filename:= AFileName;
459    except
460      on E: Exception do
461      begin
462        MsgBadConfig(AFileName, E.Message);
463        DoPyEvent_AppState(APPSTATE_SESSION_LOAD_FAIL);
464        exit;
465      end;
466    end;
467
468    FSessionIsLoading:= true;
469    DoOps_LoadHistory_GroupView(cfg); //reads to variables
470    DoApplyInitialGroupSizes; //applies that variables
471
472    cfg.EnumSubKeys('/', list);
473    list.Sort;
474
475    for i:= 0 to list.Count-1 do
476    begin
477      //handle only sections like "000".."001"..etc, ignore sections like "panels", "gr"
478      item_path:= list[i];
479      if not IsHistorySectionForFilename(item_path) then Continue;
480      item_path:= '/'+item_path+'/';
481      item_path2:= item_path+'pair/';
482
483      sFilename:= AppExpandHomeDirInFilename(cfg.GetValue(item_path+'file', ''));
484      sFilename2:= AppExpandHomeDirInFilename(cfg.GetValue(item_path2+'file', ''));
485
486      bExist:= (sFilename<>'') and FileExists(sFilename);
487      bExist2:= (sFilename2<>'') and FileExists(sFilename2);
488
489      if (sFilename<>'') and not bExist then
490      begin
491        MsgLogConsole(Format(msgCannotFindSessionFile, [sFilename]));
492      end;
493
494      if (sFilename2<>'') and not bExist2 then
495      begin
496        MsgLogConsole(Format(msgCannotFindSessionFile, [sFilename2]));
497        sFilename2:= '';
498      end;
499
500      sText:= cfg.GetValue(item_path+'text', '');
501      sKind:= cfg.GetValue(item_path+'kind', '');
502      bModified:= cfg.GetValue(item_path+'modified', false);
503      if sText='' then //don't load this file from session
504        bModified:= false;
505
506      //support old sessions with 1-based group index
507      nIndex:= cfg.GetValue(item_path+'group', 1)-1;
508
509      //check, if text saved in session, but file was changed outside
510      if bModified and bExist then
511      begin
512        sDateSaved:= cfg.GetValue(item_path+'file_date', '');
513        sDateCurrent:= FormatFileDateAsNiceString(sFilename);
514        if sDateSaved<>sDateCurrent then
515          if MsgBox(
516            msgConfirmFileChangedOutside+#10+sFilename+#10#10+
517            msgConfirmReloadIt+#10+
518            msgConfirmReloadItHotkeysSess,
519            MB_YESNO+MB_ICONQUESTION)=ID_YES then
520           bModified:= false;
521      end;
522
523      if (nIndex<0) or (nIndex>High(TATGroupsNums)) then
524        nIndex:= 0;
525      Pages:= Groups.Pages[nIndex];
526
527      if SBeginsWith(sKind, 'bin') then
528      begin
529        nIndex:= StrToIntDef(sKind[Length(sKind)], -1);
530        case nIndex of
531          0: sOpenOptions:= '/view-text';
532          1: sOpenOptions:= '/view-binary';
533          2: sOpenOptions:= '/view-hex';
534          3: sOpenOptions:= '/view-unicode';
535          4: sOpenOptions:= '/view-uhex';
536          else sOpenOptions:= '/view-binary';
537        end;
538      end
539      else
540        sOpenOptions:= '';
541
542      Frame:= nil;
543      //modified tabs must restore text, and set filename (if not empty)
544      if bModified then
545      begin
546        Inc(nCountFilesModified);
547        if (FrameCount>0) and Frames[0].IsEmpty then
548          Frame:= Frames[0]
549        else
550          Frame:= DoFileOpen('', '', Pages, SOptionPassive+SOptionNoHistory);
551        if sFilename<>'' then
552        begin
553          Frame.FileName:= sFilename;
554          Frame.TabCaption:= ExtractFileName(sFilename);
555        end;
556        if sText<>'' then
557          Frame.Editor.Text:= sText;
558        Frame.Editor.Modified:= bModified;
559        sTabTitle:= cfg.GetValue(item_path+'tab_title', '');
560        if sTabTitle<>'' then
561          Frame.TabCaption:= sTabTitle;
562        Frame.UpdateModified(Frame.Editor);
563      end
564      else
565      //unmodified+named tabs must load file again
566      if bExist then
567      begin
568        Inc(nCountFiles);
569        if sFilename2<>'' then
570          Inc(nCountFiles);
571        Frame:= DoFileOpen(sFilename, sFilename2, Pages, sOpenOptions+SOptionPassive+SOptionNoHistory);
572      end;
573
574      if Assigned(Frame) then
575      begin
576        Frame.InSession:= true;
577        Frame.DoLoadHistoryEx(Frame.Ed1, cfg, item_path, true);
578
579        if sFilename2<>'' then
580          Frame.DoLoadHistoryEx(Frame.Ed2, cfg, item_path2, true);
581
582        Frame.TabPinned:= cfg.GetValue(item_path+'pinned', false);
583
584        //event on_open was blocked in DoFileOpen, call it here
585        //(plugin "Tab Icons" needs it)
586        SetLength(Params, 0);
587        DoPyEvent(Frame.Ed1, cEventOnOpen, Params);
588      end;
589    end;
590
591    //restore tab-index in all groups
592    for i:= Low(TATGroupsNums) to High(TATGroupsNums) do
593    begin
594      CurTabs:= Groups.Pages[i].Tabs;
595      nIndex:= cfg.GetValue('/tab_index/g'+IntToStr(i), -1);
596      nIndex:= Max(0, Min(nIndex, CurTabs.TabCount-1));
597      with CurTabs do
598       if TabCount>0 then
599        if TabIndex<>nIndex then
600          TabIndex:= nIndex
601        else
602        //default TabIndex is 0, but we need to show tab anyway
603        if TabIndex=0 then
604          TabIndex:= 0;
605    end;
606
607    //restore group-index
608    nIndex:= cfg.GetValue('/tab_index/g_active', Low(TATGroupsNums));
609    if (nIndex>=Low(TATGroupsNums)) and (nIndex<=High(TATGroupsNums)) then
610     if Groups.Pages[nIndex].Tabs.TabCount>0 then
611      if Groups.PagesCurrent<>Groups.Pages[nIndex] then
612      begin
613        Groups.PagesCurrent:= Groups.Pages[nIndex];
614        with Groups.PagesCurrent do
615          Tabs.TabIndex:= Tabs.TabIndex;
616      end;
617
618    //clear tick values, to CudaExt tab switcher feels good
619    //(it shows frames with tick=0 in second listbox)
620    for i:= 0 to FrameCount-1 do
621    begin
622      Frame:= Frames[i];
623      if Frame.Visible then
624        Frame.ActivationTime:= GetTickCount64
625      else
626        Frame.ActivationTime:= 0;
627    end;
628
629    //restore panel sizes
630    if AllowShowPanels then
631    begin
632      AppPanels[cPaneSide].Visible:= cfg.GetValue('/panels/side_show', AppPanels[cPaneSide].Visible);
633      AppPanels[cPaneOut].Visible:= cfg.GetValue('/panels/bottom_show', AppPanels[cPaneOut].Visible);
634    end;
635
636    with AppPanels[cPaneSide] do
637      PanelSize:= Min(cfg.GetValue('/panels/side_size', PanelSize), ClientWidth div 2);
638
639    with AppPanels[cPaneOut] do
640      PanelSize:= Min(cfg.GetValue('/panels/bottom_size', PanelSize), ClientHeight div 2);
641
642    SText:= cfg.GetValue('/panels/side_panel', '');
643    if AppPanels[cPaneSide].Visible and (SText<>'') then
644      AppPanels[cPaneSide].UpdatePanels(SText, false, true);
645
646    SText:= cfg.GetValue('/panels/bottom_panel', '');
647    if AppPanels[cPaneOut].Visible and (SText<>'') then
648      AppPanels[cPaneOut].UpdatePanels(SText, false, true);
649
650    Result:= true;
651  finally
652    FSessionIsLoading:= false;
653    list.Free;
654    cfg.Free;
655  end;
656
657  nTick:= (GetTickCount64-nTick) div 10 * 10;
658
659  if UiOps.LogSessions then
660  begin
661    sText:= 'Loaded session: "'+ExtractFileName(AFileName)+'", '+IntToStr(nTick)+'ms, '+IntToStr(nCountFiles)+' file(s)';
662    if nCountFilesModified>0 then
663      sText+= ' + '+IntToStr(nCountFilesModified)+' modified';
664    MsgLogConsole(sText);
665  end;
666
667  //don't wait until plugin sets session name in PROC_SET_SESSION,
668  //it's needed in on_state
669  AppSessionName:= AFileName;
670
671  if (nCountFilesBefore>0) or (nCountFiles>0) then
672    DoPyEvent_AppState(APPSTATE_SESSION_LOAD)
673  else
674    DoPyEvent_AppState(APPSTATE_SESSION_LOAD_FAIL)
675end;
676
677procedure TfmMain.DoOps_LoadHistory_GroupView(cfg: TJsonConfig);
678var
679  Sep: TATStringSeparator;
680  i: integer;
681begin
682  FOption_GroupMode:= TATGroupsMode(cfg.GetValue('groups', Ord(gmOne)));
683
684  Sep.Init(cfg.GetValue('/gr/panel', ''));
685  Sep.GetItemInt(FOption_GroupPanelSize.x, 50);
686  Sep.GetItemInt(FOption_GroupPanelSize.y, 50);
687
688  Sep.Init(cfg.GetValue('/gr/pages', ''));
689  for i in TATGroupsNums do
690  begin
691    Sep.GetItemInt(FOption_GroupSizes[i].x, 50);
692    Sep.GetItemInt(FOption_GroupSizes[i].y, 50);
693  end;
694end;
695
696procedure TfmMain.DoOps_SaveHistory_GroupView(cfg: TJsonConfig);
697var
698  SizePanel: TPoint;
699  SizePage: TATGroupsPoints;
700  S: string;
701  i: integer;
702begin
703  cfg.SetValue('groups', Ord(Groups.Mode));
704
705  Groups.GetSizes(SizePanel, SizePage);
706
707  S:= '';
708  for i in TATGroupsNums do
709    S+= Format('%d,%d,', [SizePage[i].x, SizePage[i].y]);
710
711  cfg.SetValue('/gr/panel', Format('%d,%d', [SizePanel.x, SizePanel.y]));
712  cfg.SetValue('/gr/pages', S);
713end;
714
715
716procedure DoOps_LoadFormRect(Cfg: TJSONConfig; const APath: string; var R: TRect);
717var
718  S: string;
719begin
720  S:= Cfg.GetValue(APath, '');
721  if S<>'' then
722  begin
723    RectSetFromString(R, S, false);
724    FixRectPositionToDesktop(R);
725  end;
726end;
727
728
729procedure TfmMain.DoOps_LoadHistory;
730//this should be called in OnCreate, to fix window flickering if window
731//was maximized (Win32).
732var
733  cfg: TJSONConfig;
734  bFlag: boolean;
735  NTick: QWord;
736begin
737  NTick:= GetTickCount64;
738
739  AppFileCheckForNullBytes(AppFile_History);
740
741  cfg:= TJSONConfig.Create(nil);
742  try
743    try
744      cfg.Filename:= AppFile_History;
745    except
746      exit;
747    end;
748
749    DoOps_LoadFormRect(cfg, '/pos/main', FBoundsMain);
750    DoOps_LoadFormRect(cfg, '/pos/side', AppPanels[cPaneSide].FormFloatBounds);
751    DoOps_LoadFormRect(cfg, '/pos/bottom', AppPanels[cPaneOut].FormFloatBounds);
752    DoOps_LoadFormRect(cfg, '/pos/g1', FBoundsFloatGroups1);
753    DoOps_LoadFormRect(cfg, '/pos/g2', FBoundsFloatGroups2);
754    DoOps_LoadFormRect(cfg, '/pos/g3', FBoundsFloatGroups3);
755
756    //note: BoundsRect change works very long (150-200ms) on Linux gtk2
757    BoundsRect:= FBoundsMain;
758
759    FLastMaximized:= cfg.GetValue('/pos/main_max', false);
760    FLastMaximizedMonitor:= cfg.GetValue('/pos/main_mon', 0);
761
762    //console
763    if Assigned(fmConsole) then
764      cfg.GetValue('/list_console', fmConsole.EdInput.Items, '');
765
766    ////recents
767    cfg.GetValue('/recent_files', AppListRecents, '');
768    UpdateMenuRecent(nil);
769
770    ////finder
771    FFinder.OptRegex:= cfg.GetValue('/finder/regex', false);
772    FFinder.OptRegexSubst:= cfg.GetValue('/finder/regex_subst', true);
773    FFinder.OptCase:= cfg.GetValue('/finder/case', false);
774    FFinder.OptWords:= cfg.GetValue('/finder/words', false);
775    FFinder.OptBack:= cfg.GetValue('/finder/back', false);
776    FFinder.OptConfirmReplace:= cfg.GetValue('/finder/confirm', false);
777    FFinder.OptWrapped:= cfg.GetValue('/finder/wrap', false);
778    FFinder.OptInSelection:= cfg.GetValue('/finder/insel', false);
779    FFinder.OptTokens:= TATFinderTokensAllowed(cfg.GetValue('/finder/tokens', 0));
780
781    ////state
782    case UiOps.SidepanelOnStart of
783      0: bFlag:= cfg.GetValue('show_sidepanel', true);
784      1: bFlag:= true;
785      2: bFlag:= false;
786    end;
787    AppPanels[cPaneSide].Visible:= bFlag;
788
789    case UiOps.BottomOnStart of
790      0: bFlag:= cfg.GetValue('show_bottom', false);
791      1: bFlag:= true;
792      2: bFlag:= false;
793    end;
794    AppPanels[cPaneOut].Visible:= bFlag;
795
796    AppPanels[cPaneSide].PanelSize:= Min(cfg.GetValue('size_side', 200), ClientWidth div 2);
797    AppPanels[cPaneOut].PanelSize:= Min(cfg.GetValue('size_bottom', 120), ClientHeight div 2);
798
799    AppPanels[cPaneSide].Floating:= cfg.GetValue('float_side', false);
800    AppPanels[cPaneOut].Floating:= cfg.GetValue('float_bottom', false);
801
802    //note: reading 'theme_ui', 'theme_syntax' from history is deprecated in 2019.09
803    //now it's read from user.json
804    if UiOps.ThemeUi_Loaded then
805      ThemeUi:= UiOps.ThemeUi
806    else
807      ThemeUi:= cfg.GetValue('theme_ui', '');
808
809    if UiOps.ThemeSyntax_Loaded then
810      ThemeSyntax:= UiOps.ThemeSyntax
811    else
812      ThemeSyntax:= cfg.GetValue('theme_syntax', '');
813
814    UiOps.LangName:= cfg.GetValue('lang', '');
815    if UiOps.LangName<>'' then
816      DoLocalize;
817
818    if FOption_AllowSessionLoad=aalsEnable then
819    begin
820      AppSessionName:= cfg.GetValue('session', AppSessionName);
821      if not IsDefaultSessionActive then
822      begin
823        AppSessionName:= AppExpandFileNameWithDir(AppSessionName, AppDir_Settings);
824        if not FileExists(AppSessionName) then
825          AppSessionName:= '';
826      end;
827
828      FLastSelectedCommand:= cfg.GetValue('last_cmd', FLastSelectedCommand);
829      DoOps_LoadHistory_GroupView(cfg);
830    end;
831
832    FOption_SidebarTab:= cfg.GetValue('tab_left', '');
833  finally
834    cfg.Free;
835  end;
836
837  if UiOps.LogConsoleDetailedStartupTime then
838  begin
839    NTick:= GetTickCount64-NTick;
840    MsgLogConsole(Format('Loaded history: %dms', [NTick]));
841  end;
842end;
843
844
845procedure TfmMain.DoApplyInitialSidebarPanel;
846var
847  S: string;
848begin
849  //if session was loaded on start, and sidepanel was inited, exit
850  if AppPanels[cPaneSide].LastActivePanel<>'' then exit;
851
852  S:= FOption_SidebarTab;
853  //if plugin didn't load, caption not valid
854  if AppPanels[cPaneSide].CaptionToButtonIndex(S)<0 then
855    S:= msgPanelTree_Init;
856
857  if (S<>'-') and (S<>'') then
858    if AppPanels[cPaneSide].Visible then
859      AppPanels[cPaneSide].UpdatePanels(S, false, true);
860end;
861
862procedure TfmMain.DoApplyInitialWindowPos;
863var
864  Sep: TATStringSeparator;
865  NLeft, NTop, NWidth, NHeight: integer;
866begin
867  if FOption_WindowPos<>'' then
868  begin
869    Sep.Init(FOption_WindowPos);
870    Sep.GetItemInt(NLeft, Left);
871    Sep.GetItemInt(NTop, Top);
872    Sep.GetItemInt(NWidth, Width);
873    Sep.GetItemInt(NHeight, Height);
874    SetBounds(NLeft, NTop, NWidth, NHeight);
875  end;
876end;
877
878procedure TfmMain.DoApplyInitialGroupSizes;
879//groups sizes must be restored in OnShow, OnCreate is too early
880begin
881  UpdateGroupsMode(FOption_GroupMode);
882  Groups.SetSizes(FOption_GroupPanelSize, FOption_GroupSizes);
883  Groups.SaveSplitPos; //apply current sizes to internal Groups vars
884end;
885
886
887procedure TfmMain.DoOps_LoadOptionsFromString(const AString: string);
888var
889  fn: string;
890begin
891  if AString='' then exit;
892  fn:= GetTempFileName+'.json';
893
894  with TFileStream.Create(fn, fmCreate) do
895  try
896    WriteBuffer(AString[1], Length(AString));
897  finally
898    Free;
899  end;
900
901  if FileExists(fn) then
902  try
903    DoOps_LoadOptions(fn, EditorOps);
904    DoApplyAllOps;
905  finally
906    DeleteFileUTF8(fn);
907  end;
908end;
909
910procedure TfmMain.DoOps_LoadOptions_Global(cfg: TJSONConfig);
911const
912  cCharEllipsis = $2026;
913var
914  Sep: TATStringSeparator;
915  List: TStringList;
916  s: string;
917  N: integer;
918begin
919  Application.MainFormOnTaskBar:= cfg.GetValue('ui_taskbar_mode'+cOptionSystemSuffix, Application.MainFormOnTaskBar);
920
921  ATEditorOptions.FlickerReducingPause:= cfg.GetValue('renderer_anti_flicker'+cOptionSystemSuffix, ATEditorOptions.FlickerReducingPause);
922  ATEditorOptions.CharSizeProportional:= cfg.GetValue('unicode_proportional', ATEditorOptions.CharSizeProportional);
923  ATEditorOptions.CharScaleFullWidth:= cfg.GetValue('unicode_full_width', ATEditorOptions.CharScaleFullWidth);
924  ATEditorOptions.BookmarksAutoDelete:= cfg.GetValue('auto_delete_bookmarks', ATEditorOptions.BookmarksAutoDelete);
925  ATEditorOptions.DebugTiming:= cfg.GetValue('log_timing', ATEditorOptions.DebugTiming);
926
927  ATEditorOptions.MouseDragDropFocusesTargetEditor:= cfg.GetValue('mouse_drag_drop_focus_target', ATEditorOptions.MouseDragDropFocusesTargetEditor);
928  ATEditorOptions.MaxTabPositionToExpand:= cfg.GetValue('tab_max_pos_expanded', ATEditorOptions.MaxTabPositionToExpand);
929  ATEditorOptions.MaxLineLenForAccurateCharWidths:= cfg.GetValue('max_line_len_for_accurate_width', ATEditorOptions.MaxLineLenForAccurateCharWidths);
930
931  ATEditorOptions.UnprintedTabCharLength:= cfg.GetValue('unprinted_tab_len', ATEditorOptions.UnprintedTabCharLength);
932  ATEditorOptions.UnprintedReplaceSpec:= cfg.GetValue('unprinted_replace_spec', ATEditorOptions.UnprintedReplaceSpec);
933  s:= cfg.GetValue('unprinted_replace_to_code', 'A4');
934  ATEditorOptions.UnprintedReplaceSpecToCode:= StrToIntDef('$'+s, ATEditorOptions.UnprintedReplaceSpecToCode);
935
936  s:= cfg.GetValue('unprinted_symbols_scale', '');
937  if s<>'' then
938  begin
939    Sep.Init(s);
940    Sep.GetItemInt(ATEditorOptions.UnprintedSpaceDotScale, ATEditorOptions.UnprintedSpaceDotScale, 5, 100);
941    Sep.GetItemInt(ATEditorOptions.UnprintedEndDotScale, ATEditorOptions.UnprintedEndDotScale, 5, 100);
942    Sep.GetItemInt(ATEditorOptions.UnprintedEndFontScale, ATEditorOptions.UnprintedEndFontScale * 10 div 6, 5, 100);
943    ATEditorOptions.UnprintedEndFontScale:= ATEditorOptions.UnprintedEndFontScale * 6 div 10;
944    Sep.GetItemInt(ATEditorOptions.UnprintedTabPointerScale, ATEditorOptions.UnprintedTabPointerScale, 0, 100);
945  end;
946
947  ATEditorOptions.SpeedScrollAutoVert:= cfg.GetValue('mouse_scroll_speed_vert', ATEditorOptions.SpeedScrollAutoVert);
948
949  EControlOptions.AutoFoldComments:= cfg.GetValue('auto_fold_comments', 0);
950  EControlOptions.MaxLinesWhenParserEnablesFolding:= cfg.GetValue('lexer_folding_max_lines',
951    EControlOptions.MaxLinesWhenParserEnablesFolding);
952
953  ATFlatTheme.EnableColorBgOver:= cfg.GetValue('ui_button_hover', ATFlatTheme.EnableColorBgOver);
954
955  s:= cfg.GetValue('scrollbar_arrows', '');
956  if s<>'' then
957  begin
958    Sep.Init(s);
959    if Sep.GetItemInt(N, -1) then
960      if (N>=0) and (N<=Ord(High(TATScrollbarArrowsStyle))) then
961        ATScrollbarTheme.ArrowStyleH:= TATScrollbarArrowsStyle(N);
962    if Sep.GetItemInt(N, -1) then
963      if (N>=0) and (N<=Ord(High(TATScrollbarArrowsStyle))) then
964        ATScrollbarTheme.ArrowStyleV:= TATScrollbarArrowsStyle(N);
965  end;
966
967  s:= cfg.GetValue('renderer_tweaks'+cOptionSystemSuffix,
968    {$ifdef darwin}
969    ''
970    {$else}
971      {$ifdef windows}
972      'wo'
973      {$else}
974      'w'
975      {$endif}
976    {$endif} );
977  if Pos('e', s)>0 then
978    ATSynEdit_CharSizeArray.FixedSizes[cCharEllipsis]:= uw_normal
979  else
980    ATSynEdit_CharSizeArray.FixedSizes[cCharEllipsis]:= uw_fullwidth;
981  ATEditorOptions.PreciseCalculationOfCharWidth:= Pos('w', s)=0;
982  ATEditorOptions.TextoutNeedsOffsets:= Pos('o', s)>0;
983  ATEditorOptions.CaretTextOverInvertedRect:= Pos('c', s)>0;
984
985  ATScrollbarTheme.DirectJumpOnClickPageUpDown:= cfg.GetValue('scrollbar_click_jump',
986    ATScrollbarTheme.DirectJumpOnClickPageUpDown);
987
988  //additional complex options with sub-keys
989  List:= TStringList.Create;
990  try
991    cfg.EnumValues('/plugin_groups', List);
992    for s in List do
993      AppConfig_PGroups.Add(s, cfg.GetValue('/plugin_groups/'+s, ''));
994
995    cfg.EnumValues('/detect', List);
996    for s in List do
997      AppConfig_Detect.Add(s, cfg.GetValue('/detect/'+s, ''));
998
999    cfg.EnumValues('/detect_line', List);
1000    for s in List do
1001      AppConfig_DetectLine.Add(s, cfg.GetValue('/detect_line/'+s, ''));
1002  finally
1003    FreeAndNil(List);
1004  end;
1005end;
1006
1007procedure TfmMain.DoOps_LoadOptions_Editor(cfg: TJSONConfig; var Op: TEditorOps);
1008begin
1009  Op.OpFontName:= cfg.GetValue(OpStr_FontName, Op.OpFontName);
1010  Op.OpFontName_i:= cfg.GetValue(OpStr_FontName_i, Op.OpFontName_i);
1011  Op.OpFontName_b:= cfg.GetValue(OpStr_FontName_b, Op.OpFontName_b);
1012  Op.OpFontName_bi:= cfg.GetValue(OpStr_FontName_bi, Op.OpFontName_bi);
1013
1014  Op.OpFontSize:= Abs(cfg.GetValue(OpStr_FontSize, Op.OpFontSize)); //Abs() for macOS
1015  Op.OpFontSize_i:= Abs(cfg.GetValue(OpStr_FontSize_i, Op.OpFontSize_i));
1016  Op.OpFontSize_b:= Abs(cfg.GetValue(OpStr_FontSize_b, Op.OpFontSize_b));
1017  Op.OpFontSize_bi:= Abs(cfg.GetValue(OpStr_FontSize_bi, Op.OpFontSize_bi));
1018  Op.OpFontSize_original:= Op.OpFontSize;
1019  Op.OpFontSize_original_i:= Op.OpFontSize_i;
1020  Op.OpFontSize_original_b:= Op.OpFontSize_b;
1021  Op.OpFontSize_original_bi:= Op.OpFontSize_bi;
1022
1023  Op.OpFontQuality:= TFontQuality(cfg.GetValue(OpStr_FontQuality, Ord(Op.OpFontQuality)));
1024  Op.OpFontLigatures:= cfg.GetValue(OpStr_FontLigatures, Op.OpFontLigatures);
1025
1026  Op.OpActiveBorderRaw:= cfg.GetValue('ui_active_border', Op.OpActiveBorderRaw);
1027  Op.OpActiveBorderInControls:= Op.OpActiveBorderRaw > 0;
1028  Op.OpActiveBorderInEditor:= Op.OpActiveBorderRaw >= 100;
1029  Op.OpActiveBorderWidth:= Op.OpActiveBorderRaw mod 100;
1030
1031  Op.OpScrollbarsNew:= cfg.GetValue('scrollbar_themed', Op.OpScrollbarsNew);
1032  Op.OpSpacingY:= cfg.GetValue('spacing_y'+cOptionSystemSuffix, Op.OpSpacingY);
1033
1034  Op.OpTabSize:= cfg.GetValue('tab_size', Op.OpTabSize);
1035  Op.OpTabSpaces:= cfg.GetValue('tab_spaces', Op.OpTabSpaces);
1036  Op.OpMaxLineLenToTokenize:= cfg.GetValue('max_line_len_parsed', Op.OpMaxLineLenToTokenize);
1037  Op.OpMaxLineLenForBracketFinder:= Op.OpMaxLineLenToTokenize; //do we need separate option?
1038
1039  Op.OpOverwriteSel:= cfg.GetValue('ovr_sel', Op.OpOverwriteSel);
1040  Op.OpOverwriteOnPaste:= cfg.GetValue('ovr_on_paste', Op.OpOverwriteOnPaste);
1041  Op.OpPasteWithEolAtLineStart:= cfg.GetValue('paste_multiline_at_line_start', Op.OpPasteWithEolAtLineStart);
1042
1043  Op.OpAutoCloseBrackets:= cfg.GetValue('auto_close_brackets', Op.OpAutoCloseBrackets);
1044  Op.OpAutocompleteAutoshowCharCount:= cfg.GetValue('autocomplete_autoshow_chars', Op.OpAutocompleteAutoshowCharCount);
1045  Op.OpAutocompleteTriggerChars:= cfg.GetValue('autocomplete_trigger_chars', Op.OpAutocompleteTriggerChars);
1046  Op.OpAutocompleteCommitChars:= cfg.GetValue('autocomplete_commit_chars', Op.OpAutocompleteCommitChars);
1047  Op.OpAutocompleteCloseChars:= cfg.GetValue('autocomplete_close_chars', Op.OpAutocompleteCloseChars);
1048  Op.OpAutocompleteAddOpeningBracket:= cfg.GetValue('autocomplete_add_opening_bracket', Op.OpAutocompleteAddOpeningBracket);
1049  Op.OpAutocompleteUpDownAtEdge:= cfg.GetValue('autocomplete_up_down_at_edge', Op.OpAutocompleteUpDownAtEdge);
1050  Op.OpAutocompleteCommitIfSingleItem:= cfg.GetValue('autocomplete_commit_single_item', Op.OpAutocompleteCommitIfSingleItem);
1051
1052  Op.OpUnderlineColorFiles:= cfg.GetValue('underline_color_files', Op.OpUnderlineColorFiles);
1053  Op.OpUnderlineColorSize:= cfg.GetValue('underline_color_size', Op.OpUnderlineColorSize);
1054
1055  Op.OpLinks:= cfg.GetValue('links_hilite', Op.OpLinks);
1056  Op.OpLinksRegex:= cfg.GetValue('links_regex', Op.OpLinksRegex);
1057
1058  Op.OpGutterShow:= cfg.GetValue('gutter_show', Op.OpGutterShow);
1059  Op.OpGutterFold:= cfg.GetValue('gutter_fold', Op.OpGutterFold);
1060  Op.OpGutterFoldAlways:= cfg.GetValue('gutter_fold_always', Op.OpGutterFoldAlways);
1061  Op.OpGutterFoldIcons:= cfg.GetValue('gutter_fold_icons', Op.OpGutterFoldIcons);
1062  Op.OpGutterBookmarks:= cfg.GetValue('gutter_bookmarks', Op.OpGutterBookmarks);
1063
1064  Op.OpNumbersShow:= cfg.GetValue('numbers_show', Op.OpNumbersShow);
1065  //Op.OpNumbersFontSize:= cfg.GetValue('numbers_font_size', Op.OpNumbersFontSize);
1066  Op.OpNumbersStyle:= cfg.GetValue('numbers_style', Op.OpNumbersStyle);
1067  Op.OpNumbersForCarets:= cfg.GetValue('numbers_for_carets', Op.OpNumbersForCarets);
1068  Op.OpNumbersCenter:= cfg.GetValue('numbers_center', Op.OpNumbersCenter);
1069
1070  Op.OpRulerShow:= cfg.GetValue('ruler_show', Op.OpRulerShow);
1071  Op.OpRulerNumeration:= cfg.GetValue('ruler_numeration', Op.OpRulerNumeration);
1072  Op.OpRulerMarkCaret:= cfg.GetValue('ruler_mark_caret', Op.OpRulerMarkCaret);
1073  //Op.OpRulerTextIndent:= cfg.GetValue('ruler_text_indent', Op.OpRulerTextIndent);
1074
1075  Op.OpMinimapShow:= cfg.GetValue('minimap_show', Op.OpMinimapShow);
1076  Op.OpMinimapShowSelAlways:= cfg.GetValue('minimap_sel_always', Op.OpMinimapShowSelAlways);
1077  Op.OpMinimapShowSelBorder:= cfg.GetValue('minimap_sel_border', Op.OpMinimapShowSelBorder);
1078  Op.OpMinimapCharWidth:= cfg.GetValue('minimap_char_width', Op.OpMinimapCharWidth);
1079  Op.OpMinimapAtLeft:= cfg.GetValue('minimap_at_left', Op.OpMinimapAtLeft);
1080  Op.OpMinimapScale:= cfg.GetValue('minimap_scale', Op.OpMinimapScale);
1081  Op.OpMinimapTooltipShow:= cfg.GetValue('minimap_tooltip_show', Op.OpMinimapTooltipShow);
1082  Op.OpMinimapTooltipLineCount:= cfg.GetValue('minimap_tooltip_line_count', Op.OpMinimapTooltipLineCount);
1083  Op.OpMinimapTooltipWidth:= cfg.GetValue('minimap_tooltip_width', Op.OpMinimapTooltipWidth);
1084  Op.OpMinimapDragImmediately:= cfg.GetValue('minimap_drag_immediately', Op.OpMinimapDragImmediately);
1085
1086  Op.OpMicromapShow:= cfg.GetValue('micromap_show', Op.OpMicromapShow);
1087  Op.OpMicromapOnScrollbar:= cfg.GetValue('micromap_on_scrollbar', Op.OpMicromapOnScrollbar);
1088  Op.OpMicromapLineStates:= cfg.GetValue('micromap_line_states', Op.OpMicromapLineStates);
1089  Op.OpMicromapBookmarks:= cfg.GetValue('micromap_bookmarks', Op.OpMicromapBookmarks);
1090
1091  Op.OpMarginFixed:= cfg.GetValue('margin', Op.OpMarginFixed);
1092  Op.OpMarginString:= cfg.GetValue('margin_string', Op.OpMarginString);
1093  Op.OpMarkerSize:= cfg.GetValue('marker_size', Op.OpMarkerSize);
1094  Op.OpStaplesStyle:= cfg.GetValue('staples_style', Op.OpStaplesStyle);
1095  Op.OpStaplesProps:= cfg.GetValue('staples_props', Op.OpStaplesProps);
1096
1097  Op.OpUnprintedShow:= cfg.GetValue('unprinted_show', Op.OpUnprintedShow);
1098  Op.OpUnprintedContent:= cfg.GetValue('unprinted_content', Op.OpUnprintedContent);
1099
1100  Op.OpBracketHilite:= cfg.GetValue('bracket_highlight', Op.OpBracketHilite);
1101  Op.OpBracketSymbols:= cfg.GetValue('bracket_symbols', op.OpBracketSymbols);
1102  Op.OpBracketDistance:= cfg.GetValue('bracket_distance', op.OpBracketDistance);
1103
1104  Op.OpWrapMode:= cfg.GetValue('wrap_mode', Op.OpWrapMode);
1105  Op.OpWrapIndented:= cfg.GetValue('wrap_indented', Op.OpWrapIndented);
1106  Op.OpWrapEnabledMaxLines:= cfg.GetValue('wrap_enabled_max_lines', Op.OpWrapEnabledMaxLines);
1107
1108  Op.OpUndoLimit:= cfg.GetValue('undo_limit', Op.OpUndoLimit);
1109  Op.OpUndoGrouped:= cfg.GetValue('undo_grouped', Op.OpUndoGrouped);
1110  Op.OpUndoAfterSave:= cfg.GetValue('undo_after_save', Op.OpUndoAfterSave);
1111  Op.OpUndoMaxCarets:= cfg.GetValue('undo_max_carets', Op.OpUndoMaxCarets);
1112  Op.OpUndoPause:= cfg.GetValue('undo_pause', Op.OpUndoPause);
1113  Op.OpUndoMouseClicks:= cfg.GetValue('undo_mouse_clicks', Op.OpUndoMouseClicks);
1114
1115  Op.OpCaretBlinkTime:= cfg.GetValue('caret_blink_time', Op.OpCaretBlinkTime);
1116  Op.OpCaretBlinkEn:= cfg.GetValue('caret_blink_en', Op.OpCaretBlinkEn);
1117  Op.OpCaretViewNormal:= cfg.GetValue('caret_view', Op.OpCaretViewNormal);
1118  Op.OpCaretViewOverwrite:= cfg.GetValue('caret_view_ovr', Op.OpCaretViewOverwrite);
1119  Op.OpCaretViewReadonly:= cfg.GetValue('caret_view_ro', Op.OpCaretViewReadonly);
1120  Op.OpCaretVirtual:= cfg.GetValue('caret_after_end', Op.OpCaretVirtual);
1121  Op.OpCaretMulti:= cfg.GetValue('caret_multi', Op.OpCaretMulti);
1122  Op.OpCaretAfterPasteColumn:= cfg.GetValue('caret_after_paste_column', Op.OpCaretAfterPasteColumn);
1123  Op.OpCaretsAddedToColumnSel:= cfg.GetValue('carets_with_column_sel', Op.OpCaretsAddedToColumnSel);
1124  Op.OpCaretsPrimitiveColumnSel:= cfg.GetValue('carets_primitive_column_sel', Op.OpCaretsPrimitiveColumnSel);
1125  Op.OpCaretKeepVisibleOnScroll:= cfg.GetValue('caret_keep_visible_on_scroll', Op.OpCaretKeepVisibleOnScroll);
1126  Op.OpCaretProximityVert:= cfg.GetValue('caret_proximity_vert', Op.OpCaretProximityVert);
1127
1128  Op.OpKeepSelFontColor:= cfg.GetValue('keep_sel_font_color', Op.OpKeepSelFontColor);
1129  Op.OpShowCurLine:= cfg.GetValue('show_cur_line', Op.OpShowCurLine);
1130  Op.OpShowCurLineMinimal:= cfg.GetValue('show_cur_line_minimal', Op.OpShowCurLineMinimal);
1131  Op.OpShowCurLineOnlyFocused:= cfg.GetValue('show_cur_line_only_focused', Op.OpShowCurLineOnlyFocused);
1132  Op.OpShowCurCol:= cfg.GetValue('show_cur_column', Op.OpShowCurCol);
1133  Op.OpShowLastLineOnTop:= cfg.GetValue('show_last_line_on_top', Op.OpShowLastLineOnTop);
1134  Op.OpShowFullBackgroundSel:= cfg.GetValue('show_full_sel_bg', Op.OpShowFullBackgroundSel);
1135  Op.OpShowFullBackgroundSyntax:= cfg.GetValue('show_full_syntax_bg', Op.OpShowFullBackgroundSyntax);
1136  Op.OpShowMouseSelFrame:= cfg.GetValue('show_mouse_sel_frame', Op.OpShowMouseSelFrame);
1137  Op.OpCopyLineIfNoSel:= cfg.GetValue('copy_line_if_no_sel', Op.OpCopyLineIfNoSel);
1138  Op.OpCutLineIfNoSel:= cfg.GetValue('cut_line_if_no_sel', Op.OpCutLineIfNoSel);
1139  Op.OpCopyColumnAlignedBySpaces:= cfg.GetValue('copy_column_aligned_by_spaces', Op.OpCopyColumnAlignedBySpaces);
1140  Op.OpSavingTrimSpaces:= cfg.GetValue('saving_trim_spaces', Op.OpSavingTrimSpaces);
1141  Op.OpSavingTrimFinalEmptyLines:= cfg.GetValue('saving_trim_final_empty', Op.OpSavingTrimFinalEmptyLines);
1142  Op.OpSavingForceFinalEol:= cfg.GetValue('saving_force_final_eol', Op.OpSavingForceFinalEol);
1143  Op.OpShowHintOnVertScroll:= cfg.GetValue('show_hint_on_vert_scroll', Op.OpShowHintOnVertScroll);
1144  Op.OpSmoothScroll:= cfg.GetValue('smooth_scroll', Op.OpSmoothScroll);
1145  Op.OpCenteringWidth:= cfg.GetValue('centering_width', Op.OpCenteringWidth);
1146  Op.OpCenteringForDistractionFree:= cfg.GetValue('centering_for_distraction_free', Op.OpCenteringForDistractionFree);
1147  Op.OpScrollStyleHorz:= cfg.GetValue('scroll_style_horz', Op.OpScrollStyleHorz);
1148
1149  Op.OpLexerDynamicHiliteEnabled:= cfg.GetValue('lexer_dynamic_hilite', Op.OpLexerDynamicHiliteEnabled);
1150  Op.OpLexerDynamicHiliteMaxLines:= cfg.GetValue('lexer_dynamic_hilite_max_lines', Op.OpLexerDynamicHiliteMaxLines);
1151  Op.OpLexerLineSeparators:= false; //cfg.GetValue('lexer_line_separators', Op.OpLexerLineSeparators);
1152
1153  Op.OpZebra:= cfg.GetValue('zebra', Op.OpZebra);
1154  Op.OpZebraStep:= cfg.GetValue('zebra_step', Op.OpZebraStep);
1155  Op.OpDimUnfocused:= cfg.GetValue('dim_unfocused', Op.OpDimUnfocused);
1156
1157  Op.OpNonWordChars:= cfg.GetValue('nonword_chars', Op.OpNonWordChars);
1158  Op.OpFoldStyle:= cfg.GetValue('fold_style', Op.OpFoldStyle);
1159  Op.OpFoldTooltipShow:= cfg.GetValue('fold_tooltip_show', Op.OpFoldTooltipShow);
1160
1161  Op.OpIndentAuto:= cfg.GetValue('indent_auto', Op.OpIndentAuto);
1162  Op.OpIndentAutoKind:= cfg.GetValue('indent_kind', Op.OpIndentAutoKind);
1163  Op.OpIndentSize:= cfg.GetValue('indent_size', Op.OpIndentSize);
1164  Op.OpIndentAutoRule:= cfg.GetValue('indent_auto_rule', Op.OpIndentAutoRule);
1165  Op.OpUnIndentKeepsAlign:= cfg.GetValue('unindent_keeps_align', Op.OpUnIndentKeepsAlign);
1166  Op.OpIndentMakesWholeLineSel:= cfg.GetValue('indent_makes_whole_line_sel', Op.OpIndentMakesWholeLineSel);
1167
1168  Op.OpMouse2ClickDragSelectsWords:= cfg.GetValue('mouse_2click_drag_select_words', Op.OpMouse2ClickDragSelectsWords);
1169  Op.OpMouseDragDrop:= cfg.GetValue('mouse_drag_drop', Op.OpMouseDragDrop);
1170  Op.OpMouseMiddleClickAction:= cfg.GetValue('mouse_middle_click', Op.OpMouseMiddleClickAction);
1171  Op.OpMouseRightClickMovesCaret:= cfg.GetValue('mouse_rt_click_moves_caret', Op.OpMouseRightClickMovesCaret);
1172  Op.OpMouseEnableColumnSelection:= cfg.GetValue('mouse_column_selection', Op.OpMouseEnableColumnSelection);
1173  Op.OpMouseHideCursorOnType:= cfg.GetValue('mouse_hide_cursor', Op.OpMouseHideCursorOnType);
1174  Op.OpMouseGutterClickSelectedLine:= cfg.GetValue('mouse_gutter_click_sel', Op.OpMouseGutterClickSelectedLine);
1175  Op.OpMouseWheelZoom:= cfg.GetValue('mouse_wheel_zoom', Op.OpMouseWheelZoom);
1176  Op.OpMouseWheelSpeedVert:= cfg.GetValue('mouse_wheel_speed_vert', Op.OpMouseWheelSpeedVert);
1177  Op.OpMouseWheelSpeedHorz:= cfg.GetValue('mouse_wheel_speed_horz', Op.OpMouseWheelSpeedHorz);
1178  Op.OpMouseClickNumberSelectsEol:= cfg.GetValue('mouse_click_number_selects_eol', Op.OpMouseClickNumberSelectsEol);
1179  Op.OpMouseClickLinks:= cfg.GetValue('mouse_click_links', Op.OpMouseClickLinks);
1180
1181  Op.OpKeyBackspaceUnindent:= cfg.GetValue('key_bksp_unindent', Op.OpKeyBackspaceUnindent);
1182  Op.OpKeyBackspaceWrap:= cfg.GetValue('key_bksp_wrap', Op.OpKeyBackspaceWrap);
1183  Op.OpKeyTabIndents:= cfg.GetValue('key_tab_indents_sel', Op.OpKeyTabIndents);
1184  Op.OpKeyHomeToNonSpace:= cfg.GetValue('key_home_to_nonspace', Op.OpKeyHomeToNonSpace);
1185  Op.OpKeyHomeEndNavigateWrapped:= cfg.GetValue('key_home_end_nav_wrapped', Op.OpKeyHomeEndNavigateWrapped);
1186  Op.OpKeyEndToNonSpace:= cfg.GetValue('key_end_to_nonspace', Op.OpKeyEndToNonSpace);
1187  Op.OpKeyPageKeepsRelativePos:= cfg.GetValue('key_page_keeps_rel_pos', Op.OpKeyPageKeepsRelativePos);
1188  Op.OpKeyPageUpDownSize:= cfg.GetValue('key_page_size', Op.OpKeyPageUpDownSize);
1189  Op.OpKeyUpDownKeepColumn:= cfg.GetValue('key_up_down_keeps_column', Op.OpKeyUpDownKeepColumn);
1190  Op.OpKeyUpDownNavigateWrapped:= cfg.GetValue('key_up_down_nav_wrapped', Op.OpKeyUpDownNavigateWrapped);
1191  Op.OpKeyUpDownAllowToEdge:= cfg.GetValue('key_up_down_allow_edge', Op.OpKeyUpDownAllowToEdge);
1192  Op.OpKeyLeftRightGoToNextLineWithCarets:= cfg.GetValue('key_left_right_wrap_with_carets', Op.OpKeyLeftRightGoToNextLineWithCarets);
1193  Op.OpKeyLeftRightSwapSel:= cfg.GetValue('key_left_right_swap_sel', Op.OpKeyLeftRightSwapSel);
1194  Op.OpKeyLeftRightSwapSelAndSelect:= cfg.GetValue('key_left_right_swap_sel_and_select', Op.OpKeyLeftRightSwapSelAndSelect);
1195end;
1196
1197
1198procedure TfmMain.DoOps_LoadOptions_Ui(cfg: TJSONConfig);
1199var
1200  S: string;
1201  element: TAppHistoryElement;
1202begin
1203  UiOps.VarFontName:= cfg.GetValue(OpStr_UiFontName, UiOps.VarFontName);
1204  UiOps.VarFontSize:= Abs(cfg.GetValue(OpStr_UiFontSize, UiOps.VarFontSize)); //Abs for macOS
1205
1206  UiOps.OutputFontName:= cfg.GetValue(OpStr_UiFontOutputName, UiOps.OutputFontName);
1207  UiOps.OutputFontSize:= Abs(cfg.GetValue(OpStr_UiFontOutputSize, UiOps.OutputFontSize)); //Abs for macOS
1208
1209  UiOps.StatusbarFontName:= cfg.GetValue(OpStr_UiFontStatusbarName, UiOps.StatusbarFontName);
1210  UiOps.StatusbarFontSize:= Abs(cfg.GetValue(OpStr_UiFontStatusbarSize, UiOps.StatusbarFontSize)); //Abs for macOS
1211
1212  UiOps.DoubleBuffered:= cfg.GetValue(OpStr_UiDoubleBuffered, UiOps.DoubleBuffered);
1213
1214  UiOps.StatusNoSel:= cfg.GetValue('ui_statusbar_no_sel', UiOps.StatusNoSel);
1215  UiOps.StatusSmallSel:= cfg.GetValue('ui_statusbar_small_sel', UiOps.StatusSmallSel);
1216  UiOps.StatusStreamSel:= cfg.GetValue('ui_statusbar_str_sel', UiOps.StatusStreamSel);
1217  UiOps.StatusColSel:= cfg.GetValue('ui_statusbar_col_sel', UiOps.StatusColSel);
1218  UiOps.StatusCarets:= cfg.GetValue('ui_statusbar_carets', UiOps.StatusCarets);
1219  UiOps.StatusPanels:= cfg.GetValue('ui_statusbar_panels', UiOps.StatusPanels);
1220  UiOps.StatusTime:= Max(1, Min(60, cfg.GetValue('ui_statusbar_time', UiOps.StatusTime)));
1221
1222  UiOps.ShowTitlePath:= cfg.GetValue('ui_title_path', UiOps.ShowTitlePath);
1223
1224  UiOps.Scale:= cfg.GetValue('ui_scale'+cOptionSystemSuffix, 0);
1225  UiOps.ScaleFont:= cfg.GetValue('ui_scale_font'+cOptionSystemSuffix, 100);
1226  if UiOps.Scale=0 then
1227    UiOps.Scale:= 100*Screen.PixelsPerInch div 96;
1228
1229  UiOps.ReopenSession:= cfg.GetValue('ui_reopen_session', UiOps.ReopenSession);
1230  UiOps.ReopenSessionWithCmdLine:= cfg.GetValue('ui_reopen_session_cmdline', UiOps.ReopenSessionWithCmdLine);
1231  if UiOps.ReopenSessionWithCmdLine then
1232    if FOption_AllowSessionLoad=aalsNotGood then
1233      FOption_AllowSessionLoad:= aalsEnable;
1234  UiOps.SessionSaveInterval:= cfg.GetValue('ui_session_save_interval', UiOps.SessionSaveInterval);
1235  UiOps.SessionSaveOnExit:= cfg.GetValue('ui_auto_save_session', UiOps.SessionSaveOnExit);
1236  UiOps.BackupLastSessions:= cfg.GetValue('ui_backup_sessions', UiOps.BackupLastSessions);
1237
1238  UiOps.PluginDialogsShowInTaskbar:= cfg.GetValue('ui_dialogs_in_taskbar'+cOptionSystemSuffix, UiOps.PluginDialogsShowInTaskbar);
1239  UiOps.OneInstance:= cfg.GetValue('ui_one_instance', UiOps.OneInstance);
1240  UiOps.UndoPersistent:= cfg.GetValue('undo_persistent', UiOps.UndoPersistent);
1241  UiOps.AllowSaveOfUnmodifiedFile:= cfg.GetValue('ui_save_always', UiOps.AllowSaveOfUnmodifiedFile);
1242
1243  UiOps.NotificationEnabled:= cfg.GetValue('ui_notif', UiOps.NotificationEnabled);
1244  UiOps.NotificationTimeSeconds:= Max(1, cfg.GetValue('ui_notif_time', UiOps.NotificationTimeSeconds)); //don't allow 0
1245  UiOps.NotificationConfirmReload:= cfg.GetValue('ui_notif_confirm', UiOps.NotificationConfirmReload);
1246
1247  UiOps.ConfirmLinksClicks:= cfg.GetValue('ui_links_confirm', UiOps.ConfirmLinksClicks);
1248
1249  UiOps.NonTextFiles:= cfg.GetValue('ui_non_text', UiOps.NonTextFiles);
1250  UiOps.NonTextFilesBufferKb:= Max(1, Min(1024, cfg.GetValue('ui_non_text_buffer', UiOps.NonTextFilesBufferKb)));
1251  UiOps.ReloadFollowTail:= cfg.GetValue('ui_reload_tail', UiOps.ReloadFollowTail);
1252  UiOps.ReloadUnsavedConfirm:= cfg.GetValue('ui_reload_unsaved_confirm', UiOps.ReloadUnsavedConfirm);
1253  UiOps.FullScreen:= cfg.GetValue('ui_fullscreen', UiOps.FullScreen);
1254
1255  UiOps.MouseGotoDefinition:= cfg.GetValue('mouse_goto_definition', UiOps.MouseGotoDefinition);
1256
1257  UiOps.Emmet_AddSlashToEmptyTags:= cfg.GetValue('emmet_add_slash_to_empty_tags', UiOps.Emmet_AddSlashToEmptyTags);
1258  UiOps.Emmet_CommentTags:= cfg.GetValue('emmet_comment_tags', UiOps.Emmet_CommentTags);
1259  UiOps.Emmet_IndentNested:= cfg.GetValue('emmet_indent_nested', UiOps.Emmet_IndentNested);
1260  UiOps.Emmet_SingleLine:= cfg.GetValue('emmet_single_line', UiOps.Emmet_SingleLine);
1261  UiOps.Emmet_TrimLineMarkers:= cfg.GetValue('emmet_trim_line_markers', UiOps.Emmet_TrimLineMarkers);
1262  UiOps.Emmet_WordWrap:= cfg.GetValue('emmet_word_wrap', UiOps.Emmet_WordWrap);
1263
1264  UiOps.HotkeyFindDialog:= cfg.GetValue('find_hotkey_find_dlg', UiOps.HotkeyFindDialog);
1265  UiOps.HotkeyReplaceDialog:= cfg.GetValue('find_hotkey_replace_dlg', UiOps.HotkeyReplaceDialog);
1266  UiOps.HotkeyFindFirst:= cfg.GetValue('find_hotkey_find_first', UiOps.HotkeyFindFirst);
1267  UiOps.HotkeyFindNext:= cfg.GetValue('find_hotkey_find_next', UiOps.HotkeyFindNext);
1268  UiOps.HotkeyFindPrev:= cfg.GetValue('find_hotkey_find_prev', UiOps.HotkeyFindPrev);
1269  UiOps.HotkeyReplaceAndFindNext:= cfg.GetValue('find_hotkey_replace', UiOps.HotkeyReplaceAndFindNext);
1270  UiOps.HotkeyReplaceNoFindNext:= cfg.GetValue('find_hotkey_replace_no_next', UiOps.HotkeyReplaceNoFindNext);
1271  UiOps.HotkeyReplaceAll:= cfg.GetValue('find_hotkey_replace_all', UiOps.HotkeyReplaceAll);
1272  UiOps.HotkeyReplaceGlobal:= cfg.GetValue('find_hotkey_replace_global', UiOps.HotkeyReplaceGlobal);
1273  UiOps.HotkeyCountAll:= cfg.GetValue('find_hotkey_count_all', UiOps.HotkeyCountAll);
1274  UiOps.HotkeyExtractAll:= cfg.GetValue('find_hotkey_extract', UiOps.HotkeyExtractAll);
1275  UiOps.HotkeySelectAll:= cfg.GetValue('find_hotkey_select_all', UiOps.HotkeySelectAll);
1276  UiOps.HotkeyMarkAll:= cfg.GetValue('find_hotkey_mark_all', UiOps.HotkeyMarkAll);
1277  UiOps.HotkeyToggleRegex:= cfg.GetValue('find_hotkey_op_regex', UiOps.HotkeyToggleRegex);
1278  UiOps.HotkeyToggleCaseSens:= cfg.GetValue('find_hotkey_op_case', UiOps.HotkeyToggleCaseSens);
1279  UiOps.HotkeyToggleWords:= cfg.GetValue('find_hotkey_op_words', UiOps.HotkeyToggleWords);
1280  UiOps.HotkeyToggleWrapped:= cfg.GetValue('find_hotkey_op_wrapped', UiOps.HotkeyToggleWrapped);
1281  UiOps.HotkeyToggleInSelect:= cfg.GetValue('find_hotkey_op_in_sel', UiOps.HotkeyToggleInSelect);
1282  UiOps.HotkeyToggleMultiline:= cfg.GetValue('find_hotkey_op_multiline', UiOps.HotkeyToggleMultiline);
1283  UiOps.HotkeyToggleConfirmRep:= cfg.GetValue('find_hotkey_op_confirm_rep', UiOps.HotkeyToggleConfirmRep);
1284  UiOps.HotkeyToggleTokens:= cfg.GetValue('find_hotkey_op_tokens', UiOps.HotkeyToggleTokens);
1285  UiOps.HotkeyToggleHiAll:= cfg.GetValue('find_hotkey_op_hi', UiOps.HotkeyToggleHiAll);
1286
1287  UiOps.LexerThemes:= cfg.GetValue('ui_lexer_themes', UiOps.LexerThemes);
1288  UiOps.LexerMenuGrouped:= cfg.GetValue('ui_lexers_grouped', UiOps.LexerMenuGrouped);
1289  UiOps.LexerPostponeUntilShown:= cfg.GetValue('lexer_postpone_until_shown', UiOps.LexerPostponeUntilShown);
1290  if not UiOps.LexerPostponeUntilShown then
1291    UiOps.AllowFrameParsing:= true;
1292
1293  UiOps.ShowMenubar:= cfg.GetValue('ui_menu_show', UiOps.ShowMenubar);
1294  UiOps.ShowStatusbar:= cfg.GetValue('ui_statusbar_show', UiOps.ShowStatusbar);
1295  UiOps.ShowToolbar:= cfg.GetValue('ui_toolbar_show', UiOps.ShowToolbar);
1296
1297  UiOps.SidebarShow:= cfg.GetValue('ui_sidebar_show', UiOps.SidebarShow);
1298  UiOps.SidebarOnRight:= cfg.GetValue('ui_sidebar_on_right', UiOps.SidebarOnRight);
1299  UiOps.SidebarTheme:= cfg.GetValue('ui_sidebar_theme', UiOps.SidebarTheme);
1300  UiOps.SidepanelOnStart:= cfg.GetValue('ui_sidepanel_on_start', UiOps.SidepanelOnStart);
1301  UiOps.BottomOnStart:= cfg.GetValue('ui_bottom_on_start', UiOps.BottomOnStart);
1302  UiOps.TreeTheme:= cfg.GetValue('ui_tree_theme', UiOps.TreeTheme);
1303  UiOps.ToolBarTheme:= cfg.GetValue('ui_toolbar_theme', UiOps.ToolBarTheme);
1304
1305  {$ifdef windows}
1306  UiOps.ThemedMainMenu:= cfg.GetValue('ui_menu_themed', UiOps.ThemedMainMenu);
1307  UiOps.ThemedMainMenuFontSize:= cfg.GetValue('ui_menu_themed_font_size', UiOps.ThemedMainMenuFontSize);
1308  {$endif}
1309
1310  {$ifndef windows}
1311  //option is ignored on win
1312  UiOps.PyLibrary:= cfg.GetValue('pylib'+cOptionSystemSuffix, UiOps.PyLibrary);
1313  {$endif}
1314
1315  UiOps.PictureTypes:= cfg.GetValue('picture_types', UiOps.PictureTypes);
1316
1317  UiOps.MaxFileSizeToOpen:= cfg.GetValue('ui_max_size_open', UiOps.MaxFileSizeToOpen);
1318  UiOps.MaxFileSizeForLexer:= cfg.GetValue('ui_max_size_lexer', UiOps.MaxFileSizeForLexer);
1319
1320  UiOps.AutocompleteHtml:= cfg.GetValue('autocomplete_html', UiOps.AutocompleteHtml);
1321  UiOps.AutocompleteHtml_AutoClose:= cfg.GetValue('autocomplete_html_autoclose', UiOps.AutocompleteHtml_AutoClose);
1322  UiOps.AutocompleteHtml_Lexers:= cfg.GetValue('autocomplete_html_lexers', UiOps.AutocompleteHtml_Lexers);
1323  UiOps.AutocompleteCss:= cfg.GetValue('autocomplete_css', UiOps.AutocompleteCss);
1324  UiOps.AutocompleteCss_Lexers:= cfg.GetValue('autocomplete_css_lexers', UiOps.AutocompleteCss_Lexers);
1325  UiOps.AutocompleteFileURI:= cfg.GetValue('autocomplete_file_uri', UiOps.AutocompleteFileURI);
1326
1327  UiOps.FindSuggestSel:= cfg.GetValue('find_suggest_sel', UiOps.FindSuggestSel);
1328  UiOps.FindSuggestWord:= cfg.GetValue('find_suggest_cur_word', UiOps.FindSuggestWord);
1329  UiOps.FindSuggestInSelection:= cfg.GetValue('find_suggest_in_selection', UiOps.FindSuggestInSelection);
1330  UiOps.FindCurrentWordCaseSensitive:= TUiOpsFindCaseSensitive(cfg.GetValue('find_sel_case', Ord(UiOps.FindCurrentWordCaseSensitive)));
1331
1332  UiOps.FindHiddenButtons:= cfg.GetValue('find_hidden_buttons', UiOps.FindHiddenButtons);
1333  UiOps.FindShow_FindFirst:=     Pos('f', UiOps.FindHiddenButtons)=0;
1334  UiOps.FindShow_FindNext:=      Pos('n', UiOps.FindHiddenButtons)=0;
1335  UiOps.FindShow_FindPrev:=      Pos('p', UiOps.FindHiddenButtons)=0;
1336  UiOps.FindShow_ReplaceAll:=    Pos('a', UiOps.FindHiddenButtons)=0;
1337  UiOps.FindShow_ReplaceGlobal:= Pos('g', UiOps.FindHiddenButtons)=0;
1338  UiOps.FindShow_RegEx:=         Pos('R', UiOps.FindHiddenButtons)=0;
1339  UiOps.FindShow_CaseSens:=      Pos('S', UiOps.FindHiddenButtons)=0;
1340  UiOps.FindShow_WholeWords:=    Pos('W', UiOps.FindHiddenButtons)=0;
1341  UiOps.FindShow_Wrapped:=       Pos('O', UiOps.FindHiddenButtons)=0;
1342  UiOps.FindShow_InSel:=         Pos('I', UiOps.FindHiddenButtons)=0;
1343  UiOps.FindShow_MultiLine:=     Pos('M', UiOps.FindHiddenButtons)=0;
1344  UiOps.FindShow_SyntaxElements:=Pos('X', UiOps.FindHiddenButtons)=0;
1345  UiOps.FindShow_HiAll:=         Pos('H', UiOps.FindHiddenButtons)=0;
1346  UiOps.FindShow_ConfirmRep:=    Pos('C', UiOps.FindHiddenButtons)=0;
1347  UiOps.FindShow_RegexSubst:=    Pos('E', UiOps.FindHiddenButtons)=0;
1348
1349  UiOps.FindIndentVert:= cfg.GetValue('find_indent_vert', UiOps.FindIndentVert);
1350  UiOps.FindIndentHorz:= cfg.GetValue('find_indent_horz', UiOps.FindIndentHorz);
1351  UiOps.FindMultiLineScale:= cfg.GetValue('find_multiline_scale', UiOps.FindMultiLineScale);
1352  UiOps.FindSeparateForm:= cfg.GetValue('find_separate_form', UiOps.FindSeparateForm);
1353  UiOps.FindHiAll_MaxLines:= cfg.GetValue('find_hi_max_lines', UiOps.FindHiAll_MaxLines);
1354  //UiOps.FindHiAll_MoveCaret:= cfg.GetValue('find_hi_move_caret', UiOps.FindHiAll_MoveCaret);
1355
1356  EditorOps.OpUndoIndentVert:= UiOps.FindIndentVert;
1357  EditorOps.OpUndoIndentHorz:= UiOps.FindIndentHorz;
1358
1359  ShowTabsMain:= cfg.GetValue('ui_tab_show', ShowTabsMain);
1360  UiOps.TabsDisabled:= cfg.GetValue('ui_tab_disabled', UiOps.TabsDisabled);
1361  UiOps.TabVarWidth:= cfg.GetValue('ui_tab_variable_width', UiOps.TabVarWidth);
1362  UiOps.TabMultiline:= cfg.GetValue('ui_tab_multiline', UiOps.TabMultiline);
1363  if ATTabsStretchDrawEnabled then
1364    UiOps.TabAngled:= cfg.GetValue('ui_tab_angled', UiOps.TabAngled);
1365  UiOps.TabFlat:= cfg.GetValue('ui_tab_flat', UiOps.TabFlat);
1366  UiOps.TabWidth:= cfg.GetValue('ui_tab_size_x', UiOps.TabWidth);
1367  UiOps.TabWidthMin:= cfg.GetValue('ui_tab_size_x_min', UiOps.TabWidthMin);
1368  UiOps.TabWidthMax:= cfg.GetValue('ui_tab_size_x_max', UiOps.TabWidthMax);
1369  UiOps.TabHeight:= cfg.GetValue('ui_tab_size_y', UiOps.TabHeight);
1370  UiOps.TabHeightInner:= UiOps.TabHeight-1;
1371  UiOps.TabSpaceBeforeText:= cfg.GetValue('ui_tab_padding', UiOps.TabSpaceBeforeText);
1372  UiOps.TabPosition:= cfg.GetValue('ui_tab_position', UiOps.TabPosition);
1373  UiOps.TabColorFull:= cfg.GetValue('ui_tab_fullcolor', UiOps.TabColorFull);
1374  UiOps.TabFontScale:= cfg.GetValue('ui_tab_font_scale', UiOps.TabFontScale);
1375  UiOps.TabShowX:= cfg.GetValue('ui_tab_show_x', UiOps.TabShowX);
1376  UiOps.TabShowXSize:= cfg.GetValue('ui_tab_show_x_size', UiOps.TabShowXSize);
1377  UiOps.TabShowXRounded:= cfg.GetValue('ui_tab_x_rounded', UiOps.TabShowXRounded);
1378  UiOps.TabShowPlus:= cfg.GetValue('ui_tab_show_plus', UiOps.TabShowPlus);
1379  UiOps.TabDblClickClose:= cfg.GetValue('ui_tab_2click_closes', UiOps.TabDblClickClose);
1380  UiOps.TabNumbers:= cfg.GetValue('ui_tab_numbers', UiOps.TabNumbers);
1381  UiOps.TabNewNearCurrent:= cfg.GetValue('ui_tab_new_near_current', UiOps.TabNewNearCurrent);
1382  UiOps.TabRecentOnClose:= cfg.GetValue('ui_tab_recent_on_close', UiOps.TabRecentOnClose);
1383  UiOps.TabButtonLayout:= cfg.GetValue('ui_tab_button_layout', UiOps.TabButtonLayout);
1384  UiOps.TabPreviewFontStyle:= cfg.GetValue('ui_tab_preview_font_style', UiOps.TabPreviewFontStyle);
1385  UiOps.TabSwitcherDialog:= cfg.GetValue('ui_tab_switcher_dialog', UiOps.TabSwitcherDialog);
1386
1387  //UiOps.ListboxCentered:= cfg.GetValue('ui_listbox_centered', UiOps.ListboxCentered);
1388  UiOps.ListboxSizeX:= cfg.GetValue('ui_listbox_size_x', UiOps.ListboxSizeX);
1389  UiOps.ListboxSizeY:= cfg.GetValue('ui_listbox_size_y', UiOps.ListboxSizeY);
1390  UiOps.ListboxCompleteSizeX:= cfg.GetValue('ui_listbox_complete_size_x', UiOps.ListboxCompleteSizeX);
1391  UiOps.ListboxCompleteSizeY:= cfg.GetValue('ui_listbox_complete_size_y', UiOps.ListboxCompleteSizeY);
1392  UiOps.ListboxFuzzySearch:= cfg.GetValue('ui_listbox_fuzzy', UiOps.ListboxFuzzySearch);
1393
1394  UiOps.MaxHistoryEdits:= Max(0, Min(200, cfg.GetValue('ui_max_history_edits', UiOps.MaxHistoryEdits)));
1395  UiOps.MaxHistoryMenu:= Max(0, Min(50, cfg.GetValue('ui_max_history_menu', UiOps.MaxHistoryMenu)));
1396  UiOps.MaxHistoryFiles:= Max(0, Min(400, cfg.GetValue('ui_max_history_files', UiOps.MaxHistoryFiles)));
1397
1398  UiOps.CmdPaletteFilterKeep:= cfg.GetValue('ui_cmdpalette_filter_keep', UiOps.CmdPaletteFilterKeep);
1399  //UiOps.CmdPaletteHideSimpleCommands:= cfg.GetValue('ui_cmdpalette_hide_simple', UiOps.CmdPaletteHideSimpleCommands);
1400
1401  UiOps.HistoryDisabledStr:= cfg.GetValue('ui_history_disabled', UiOps.HistoryDisabledStr);
1402  for element:= Low(element) to High(element) do
1403    UiOps.HistoryItems[element]:= Pos(cAppHistoryElementChar[element], UiOps.HistoryDisabledStr)=0;
1404
1405  UiOps.EscapeClose:= cfg.GetValue('ui_esc_close', UiOps.EscapeClose);
1406  UiOps.EscapeCloseConsole:= cfg.GetValue('ui_esc_close_console', UiOps.EscapeCloseConsole);
1407  UiOps.ConsoleWordWrap:= cfg.GetValue('ui_console_wrap', UiOps.ConsoleWordWrap);
1408  //UiOps.ConsoleCompact:= cfg.GetValue('ui_console_compact', UiOps.ConsoleCompact);
1409  UiOps.InitialDir:= cfg.GetValue('ui_initial_dir', UiOps.InitialDir);
1410
1411  UiOps.ExportHtmlNumbers:= cfg.GetValue('export_html_numbers', UiOps.ExportHtmlNumbers);
1412  UiOps.ExportHtmlFontName:= cfg.GetValue('export_html_font_name', UiOps.ExportHtmlFontName);
1413  UiOps.ExportHtmlFontSize:= Abs(cfg.GetValue('export_html_font_size', UiOps.ExportHtmlFontSize));
1414
1415  UiOps.TreeAutoSync:= cfg.GetValue('ui_tree_auto_sync', UiOps.TreeAutoSync);
1416  UiOps.TreeTimeFill:= cfg.GetValue('ui_tree_time_fill', UiOps.TreeTimeFill);
1417  //UiOps.TreeTimeCaret:= cfg.GetValue('ui_tree_time_focus', UiOps.TreeTimeCaret);
1418  //UiOps.TreeShowLines:= cfg.GetValue('ui_tree_show_lines', UiOps.TreeShowLines);
1419  UiOps.TreeShowIcons:= cfg.GetValue('ui_tree_icons', UiOps.TreeShowIcons);
1420  UiOps.TreeShowTooltips:= cfg.GetValue('ui_tree_show_tooltips', UiOps.TreeShowTooltips);
1421  //UiOps.TreeCache:= cfg.GetValue('ui_tree_cache', UiOps.TreeCache);
1422  UiOps.TreeFilterLayout:= cfg.GetValue('ui_tree_filter_layout', UiOps.TreeFilterLayout);
1423  UiOps.TreeSublexers:= cfg.GetValue('ui_tree_sublexers', UiOps.TreeSublexers);
1424
1425  UiOps.PyChangeSlow:= cfg.GetValue('py_change_slow', UiOps.PyChangeSlow);
1426
1427  UiOps.LogPluginIniting:= cfg.GetValue('py_init_log', UiOps.LogPluginIniting);
1428  UiOps.LogSessions:= cfg.GetValue('log_sessions', UiOps.LogSessions);
1429  //UiOps.LogDebug:= cfg.GetValue('log_debug', UiOps.LogDebug);
1430  UiOps.LogConsole:= cfg.GetValue('log_console', UiOps.LogConsole);
1431
1432  UiOps.NewdocLexer:= cfg.GetValue('newdoc_lexer', UiOps.NewdocLexer);
1433  UiOps.NewdocEnc:= cfg.GetValue('newdoc_encoding', UiOps.NewdocEnc);
1434  UiOps.NewdocEnds:= cfg.GetValue('newdoc_ends', UiOps.NewdocEnds);
1435
1436  UiOps.DefaultEncUtf8:= cfg.GetValue(OpStr_DefEncodingIsUtf8, UiOps.DefaultEncUtf8);
1437  UiOps.ViewerBinaryWidth:= cfg.GetValue('viewer_binary_width', UiOps.ViewerBinaryWidth);
1438  UiOps.ViewerNonPrintable:= cfg.GetValue('viewer_unprinted', UiOps.ViewerNonPrintable);
1439
1440  UiOps.AltTooltipTime:= cfg.GetValue('ui_alt_hint_time', UiOps.AltTooltipTime);
1441
1442  S:= cfg.GetValue('ui_theme', '?');
1443  UiOps.ThemeUi_Loaded:= S<>'?';
1444  if UiOps.ThemeUi_Loaded then
1445    UiOps.ThemeUi:= S;
1446
1447  S:= cfg.GetValue('ui_theme_syntax', '?');
1448  UiOps.ThemeSyntax_Loaded:= S<>'?';
1449  if UiOps.ThemeSyntax_Loaded then
1450    UiOps.ThemeSyntax:= S;
1451end;
1452
1453
1454procedure TfmMain.DoOps_LoadOptions(const fn: string; var Op: TEditorOps;
1455  AllowUiOps: boolean=true; AllowGlobalOps: boolean=true);
1456var
1457  cfg: TJsonConfig;
1458  NTick: QWord;
1459begin
1460  NTick:= GetTickCount64;
1461
1462  cfg:= TJsonConfig.Create(nil);
1463  try
1464    try
1465      cfg.Filename:= fn;
1466    except
1467      on E: Exception do
1468      begin
1469        MsgBadConfig(fn, E.Message);
1470        Exit
1471      end;
1472    end;
1473
1474    if AllowGlobalOps then
1475      DoOps_LoadOptions_Global(cfg);
1476
1477    if AllowUiOps then
1478      DoOps_LoadOptions_Ui(cfg);
1479
1480    DoOps_LoadOptions_Editor(cfg, Op);
1481
1482    //don't show if we only load lexer-specific config
1483    if UiOps.LogConsoleDetailedStartupTime then
1484      if AllowUiOps and AllowGlobalOps then
1485      begin
1486        NTick:= GetTickCount64-NTick;
1487        MsgLogConsole(Format('Loaded configs: %dms', [NTick]));
1488      end;
1489  finally
1490    cfg.Free;
1491  end;
1492end;
1493
1494
1495procedure TfmMain.DoOps_LoadOptionsLexerSpecific(F: TEditorFrame; Ed: TATSynEdit);
1496var
1497  Ops: TEditorOps;
1498  FilenameDefault, FilenameUser, CurLexer: string;
1499  bExistsDefault, bExistsUser: boolean;
1500  TempOps: TATEditorTempOptions;
1501begin
1502  if F=nil then exit;
1503
1504  CurLexer:= F.LexerName[Ed];
1505  FilenameDefault:= GetAppLexerSpecificConfig(CurLexer, true);
1506  FilenameUser:= GetAppLexerSpecificConfig(CurLexer, false);
1507
1508  bExistsDefault:= FileExists(FilenameDefault);
1509  bExistsUser:= FileExists(FilenameUser);
1510
1511  if bExistsDefault or bExistsUser then
1512  begin
1513    Ops:= EditorOps;
1514    EditorSaveTempOptions(Ed, TempOps);
1515
1516    if bExistsDefault then
1517    begin
1518      DoOps_LoadOptions(FilenameDefault, Ops, false, false);
1519    end;
1520
1521    if bExistsUser then
1522    begin
1523      DoOps_LoadOptions(FilenameUser, Ops, false, false);
1524    end;
1525
1526    DoApplyFrameOps(F, Ops, true);
1527    EditorRestoreTempOptions(Ed, TempOps, Ed.InitialOptions);
1528  end;
1529end;
1530
1531
1532procedure TfmMain.DoOps_DialogFont_Text;
1533begin
1534  DoOps_DialogFont(
1535    EditorOps.OpFontName,
1536    EditorOps.OpFontSize,
1537    OpStr_FontName,
1538    OpStr_FontSize);
1539  DoApplyFont_Text;
1540end;
1541
1542procedure TfmMain.DoOps_DialogFont_Ui;
1543begin
1544  DoOps_DialogFont(
1545    UiOps.VarFontName,
1546    UiOps.VarFontSize,
1547    OpStr_UiFontName,
1548    OpStr_UiFontSize);
1549  DoApplyFont_Ui;
1550end;
1551
1552procedure TfmMain.DoOps_DialogFont_Output;
1553begin
1554  DoOps_DialogFont(
1555    UiOps.OutputFontName,
1556    UiOps.OutputFontSize,
1557    OpStr_UiFontOutputName,
1558    OpStr_UiFontOutputSize);
1559  DoApplyFont_Output;
1560end;
1561
1562procedure TfmMain.DoOps_FontSizeChange(AIncrement: integer);
1563const
1564  cMinSize = 6;
1565begin
1566  EditorOps.OpFontSize   := Max(cMinSize, EditorOps.OpFontSize   +AIncrement);
1567  EditorOps.OpFontSize_i := Max(cMinSize, EditorOps.OpFontSize_i +AIncrement);
1568  EditorOps.OpFontSize_b := Max(cMinSize, EditorOps.OpFontSize_b +AIncrement);
1569  EditorOps.OpFontSize_bi:= Max(cMinSize, EditorOps.OpFontSize_bi+AIncrement);
1570  DoApplyFont_Text;
1571  DoPyEvent_EdState(nil, EDSTATE_ZOOM);
1572end;
1573
1574procedure TfmMain.DoOps_FontSizeReset;
1575begin
1576  EditorOps.OpFontSize:= EditorOps.OpFontSize_original;
1577  EditorOps.OpFontSize_i:= EditorOps.OpFontSize_original_i;
1578  EditorOps.OpFontSize_b:= EditorOps.OpFontSize_original_b;
1579  EditorOps.OpFontSize_bi:= EditorOps.OpFontSize_original_bi;
1580  DoApplyFont_Text;
1581  DoPyEvent_EdState(nil, EDSTATE_ZOOM);
1582end;
1583
1584
1585procedure TfmMain.DoOps_DialogFont(
1586  var OpName: string; var OpSize: integer;
1587  const AConfigStrName, AConfigStrSize: string);
1588var
1589  dlg: TFontDialog;
1590  cfg: TJsonConfig;
1591  fn: string;
1592begin
1593  fn:= AppFile_OptionsUser;
1594  if not FileExists(fn) then
1595  begin
1596    AppCreateFileJSON(fn);
1597    if not FileExists(fn) then exit;
1598  end;
1599
1600  dlg:= TFontDialog.Create(nil);
1601  try
1602    dlg.Font.Name:= OpName;
1603    dlg.Font.Size:= OpSize;
1604    if not dlg.Execute then exit;
1605    OpName:= dlg.Font.Name;
1606    OpSize:= dlg.Font.Size;
1607  finally
1608    FreeAndNil(dlg);
1609  end;
1610
1611  cfg:= TJSONConfig.Create(nil);
1612  try
1613    try
1614      cfg.Formatted:= true;
1615      cfg.Filename:= fn;
1616      cfg.SetValue(AConfigStrName, OpName);
1617      cfg.SetValue(AConfigStrSize, OpSize);
1618    except
1619    end;
1620  finally
1621    try
1622      cfg.Free;
1623    except
1624      MsgBox(msgCannotSaveUserConf, MB_OK or MB_ICONERROR);
1625    end;
1626  end;
1627end;
1628
1629procedure TfmMain.DoOps_LoadOptionsAndApplyAll;
1630// called by command "settings: reload/apply config"
1631var
1632  bDisFree: boolean;
1633begin
1634  bDisFree:= ShowDistractionFree;
1635  DoOps_LoadOptions(AppFile_OptionsUser, EditorOps);
1636  DoApplyAllOps;
1637
1638  MsgStatus(msgStatusReadingOps);
1639  DoPyEvent_AppState(APPSTATE_CONFIG_REREAD);
1640
1641  if bDisFree then
1642    SetShowDistractionFree_Forced;
1643end;
1644
1645
1646