1 (*
2 This Source Code Form is subject to the terms of the Mozilla Public
3 License, v. 2.0. If a copy of the MPL was not distributed with this
4 file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
6 Copyright (c) Alexey Torgashin
7 *)
8 unit proc_globdata;
9
10 {$mode objfpc}{$H+}
11 {$IOChecks off}
12 {$ModeSwitch advancedrecords}
13
14 interface
15
16 uses
17 {$ifdef windows}
18 Windows,
19 {$endif}
20 Classes, SysUtils, Forms, Controls, Menus,
21 Dialogs, Graphics,
22 StrUtils,
23 syncobjs,
24 gqueue,
25 Math,
26 InterfaceBase,
27 LclProc, LclType, LazFileUtils,
28 FileUtil,
29 IniFiles,
30 Process,
31 ATSynEdit,
32 ATSynEdit_Keymap,
33 ATSynEdit_Keymap_Init,
34 ATSynEdit_Adapter_litelexer,
35 ATSynEdit_Commands,
36 ATStringProc,
37 ATStringProc_Separator,
38 ATFlatThemes,
39 ATListbox,
40 ATStatusBar,
41 ATScrollBar,
42 ATTabs,
43 at__jsonconf,
44 proc_cmd,
45 proc_msg,
46 proc_str,
47 ec_LexerList,
48 ec_SyntAnal;
49
50 type
51
52 { TAppFileProps }
53
54 TAppFileProps = record
55 Inited: boolean;
56 Exists: boolean;
57 Size: Int64;
58 Age: LongInt;
59 class operator =(const a, b: TAppFileProps): boolean;
60 end;
61
62 TAppConsoleQueue = specialize TQueue<UnicodeString>;
63
64 TAppCommandDelayed = record
65 Code: integer;
66 Tabs: TATTabs;
67 TabIndex: integer;
68 Invoke: TATEditorCommandInvoke;
69 EdAddress: pointer;
70 EdIndex: integer;
71 end;
72
73 TAppCommandsDelayed = specialize TQueue<TAppCommandDelayed>;
74
75 var
76 AppActiveForm: TObject = nil;
77 AppThemeStatusbar: TATFlatTheme;
78 AppApiDialogCounter: integer = 0;
79
80 type
81 TApp3States = (
82 a3sOff,
83 a3sOn,
84 a3sPassive
85 );
86
87 TAppHistoryElement = (
88 ahhText,
89 ahhCaret,
90 ahhCaretSel,
91 ahhTopLine,
92 ahhTabSize,
93 ahhEncoding,
94 ahhBookmarks,
95 ahhLexer,
96 ahhWordWrap,
97 ahhMinimap,
98 ahhMicromap,
99 ahhRuler,
100 ahhUnprinted,
101 ahhLineNumbers,
102 ahhScale,
103 ahhFolding,
104 ahhMarkers,
105 ahhTabColor,
106 ahhCodeTreeFilter,
107 ahhTabSplit
108 );
109
110 const
111 cAppSessionDefault = 'history session.json';
112 cAppHistoryElementChar: array[TAppHistoryElement] of char =
113 'tchsTeblwMmrunSfkCFi';
114
115 const
116 cAppMaxGroup = Pred(6+3); //6 normal groups + 3 floating groups
117
118 var
119 //ATSynEdit has range for bookmarks 0..63, 0=none
120 AppBookmarkSetup: array[1..63] of
121 record
122 ImageIndex: integer;
123 Color: TColor;
124 end;
125 var
126 AppListRecents: TStringList = nil;
127 AppBookmarkImagelist: TImageList = nil;
128 AppApiFlatTheme: TATFlatTheme;
129 AppAlwaysNewInstance: boolean = false;
130 AppSessionName: string = '';
131 AppServerId: string = 'cudatext.0'; //used by TUniqueInstance (which is used only on Unix)
132
133 var
134 AppFrameList1: TFPList; //all frames - for main thread
135 AppFrameList2: TFPList; //all frames - for file watcher thread
136 AppFrameListDeleting: TFPList; //frames which need to be Free'd
137 //we don't free frames instantly, because watcher thread can access them
138
139 AppEventLister: TEvent; //event set to signaled, when main thread has done AppFrameList2 updating
140 AppEventWatcher: TEvent; //event set to signaled, when watcher thread is not busy
141
142 type
143 TAppKeyValue = class
144 Key: string;
145 Value: string;
146 end;
147
148 type
149 { TAppKeyValues }
150
151 TAppKeyValues = class(TFPList)
152 public
153 procedure Add(const AKey, AValue: string);
GetValuenull154 function GetValue(const AKey, ADefValue: string): string;
155 end;
156
157 var
158 AppConfig_Detect: TAppKeyValues;
159 AppConfig_DetectLine: TAppKeyValues;
160 AppConfig_PGroups: TAppKeyValues;
161
162 const
163 AppExtensionThemeUi = '.cuda-theme-ui';
164 AppExtensionThemeSyntax = '.cuda-theme-syntax';
165
166 type
167 TUiOpsFindCaseSensitive = (
168 ufcsCaseIgnore,
169 ufcsCaseSens,
170 ufcsCaseFromDialog
171 );
172
173 type
174 TUiOps = record
175 VarFontName: string;
176 VarFontSize: integer;
177 OutputFontName: string;
178 OutputFontSize: integer;
179 StatusbarFontName: string;
180 StatusbarFontSize: integer;
181 DoubleBuffered: boolean;
182
183 PyLibrary: string;
184 PyChangeSlow: integer;
185 InfoAboutOptionsEditor: boolean;
186 AllowFrameParsing: boolean; //must be set in FormMain.OnShow
187 AllowRunPkExec: boolean;
188
189 LogPluginIniting: boolean;
190 LogSessions: boolean;
191 LogDebug: boolean;
192 LogConsole: boolean;
193 LogConsoleDetailedStartupTime: boolean;
194
195 LexerThemes: boolean;
196 LexerMenuGrouped: boolean;
197 LexerPostponeUntilShown: boolean;
198 LexerParsingMinTimeForEvent: integer;
199
200 ToolBarTheme: string;
201 LangName: string;
202
203 ThemeUi: string;
204 ThemeSyntax: string;
205 ThemeUi_Loaded: boolean;
206 ThemeSyntax_Loaded: boolean;
207 ThemedMainMenu: boolean;
208 ThemedMainMenuFontName: string;
209 ThemedMainMenuFontSize: integer;
210
211 SidebarShow: boolean;
212 SidebarOnRight: boolean;
213 SidebarTheme: string;
214 SidepanelOnStart: integer;
215 BottomOnStart: integer;
216 PictureTypes: string;
217 DefaultTabSplitIsHorz: boolean;
218 MaxFileSizeToOpen: integer;
219 MaxFileSizeForLexer: integer;
220 MaxStatusbarMessages: integer;
221
222 AutocompleteHtml: boolean;
223 AutocompleteHtml_AutoClose: boolean;
224 AutocompleteHtml_Lexers: string;
225 AutocompleteCss: boolean;
226 AutocompleteCss_Lexers: string;
227 AutocompleteFileURI: boolean;
228 AutocompleteInComments: boolean;
229 AutocompleteInCommentsHTML: boolean;
230 AutocompleteInStrings: boolean;
231
232 HtmlBackgroundColorPair: array[boolean] of TColor;
233
234 ListboxCentered: boolean;
235 ListboxSizeX: integer;
236 ListboxSizeY: integer;
237 ListboxCompleteSizeX: integer;
238 ListboxCompleteSizeY: integer;
239 ListboxFuzzySearch: boolean;
240 ListboxHotkeyFontSizeDelta: integer;
241
242 TabsShowFoldersSuffix: boolean;
243 TabsShowFoldersMaxLevels: integer;
244 TabsResetUntitledCounter: boolean;
245 TabsDisabled: boolean;
246 TabVarWidth: boolean;
247 TabMultiline: boolean;
248 TabAngled: boolean;
249 TabFlat: boolean;
250 TabWidth: integer;
251 TabWidthMin: integer;
252 TabWidthMax: integer;
253 TabHeight: integer;
254 TabHeightInner: integer;
255 TabSpacer: integer;
256 TabSpaceBeforeText: integer;
257 TabPosition: integer;
258 TabColorFull: boolean;
259 TabFontScale: integer;
260 TabShowX: integer;
261 TabShowXSize: integer;
262 TabShowXRounded: boolean;
263 TabShowPlus: boolean;
264 TabDblClickClose: boolean;
265 TabNumbers: boolean;
266 TabNewNearCurrent: boolean;
267 TabRecentOnClose: boolean;
268 TabButtonLayout: string;
269 TabPreviewFontStyle: string;
270 TabSwitcherDialog: boolean;
271
272 MaxHistoryEdits: integer;
273 MaxHistoryMenu: integer;
274 MaxHistoryFiles: integer;
275
276 CmdPaletteFilterKeep: boolean;
277 CmdPaletteFilterText: string;
278
279 HistoryDisabledStr: string;
280 HistoryItems: array[TAppHistoryElement] of boolean;
281
282 FindSuggestSel: boolean;
283 FindSuggestWord: boolean;
284 FindSuggestInSelection: boolean;
285 FindCurrentWordCaseSensitive: TUiOpsFindCaseSensitive;
286 FindShowNoResultsByInputBgColor: boolean;
287
288 FindHiddenButtons: string;
289 FindShow_FindFirst: boolean;
290 FindShow_FindNext: boolean;
291 FindShow_FindPrev: boolean;
292 FindShow_ReplaceAll: boolean;
293 FindShow_ReplaceGlobal: boolean;
294 FindShow_RegEx: boolean;
295 FindShow_CaseSens: boolean;
296 FindShow_WholeWords: boolean;
297 FindShow_Wrapped: boolean;
298 FindShow_InSel: boolean;
299 FindShow_MultiLine: boolean;
300 FindShow_SyntaxElements: boolean;
301 FindShow_HiAll: boolean;
302 FindShow_ConfirmRep: boolean;
303 FindShow_RegexSubst: boolean;
304
305 FindIndentVert: integer;
306 FindIndentHorz: integer;
307 FindMultiLineScale: double;
308 FindSeparateForm: boolean;
309 FindHiAll_MaxLines: integer;
310 FindHiAll_TagValue: Int64;
311 //FindHiAll_MoveCaret: boolean;
312 FindOccur_TagValue: Int64;
313
314 AllowProgramUpdates: boolean;
315 EscapeClose: boolean;
316 EscapeCloseConsole: boolean;
317 ConsoleWordWrap: boolean;
318 InputHeight: integer;
319 InitialDir: string;
320 ConfirmLinksClicks: boolean;
321 ConfirmSaveEmptyUntitledTab: boolean;
322
323 ExportHtmlNumbers: boolean;
324 ExportHtmlFontName: string;
325 ExportHtmlFontSize: integer;
326
327 TreeTheme: string;
328 TreeAutoSync: boolean;
329 TreeTimeFill: integer;
330 //TreeTimeCaret: integer;
331 TreeShowIcons: boolean;
332 TreeShowTooltips: boolean;
333 TreeFilterLayout: integer;
334 TreeSublexers: boolean;
335 TreeIconFilenames: string;
336
337 NewdocLexer: string;
338 NewdocEnc: string;
339 NewdocEnds: integer;
340
341 DefaultEncUtf8: boolean;
342 ViewerBinaryWidth: integer;
343 ViewerNonPrintable: boolean;
344
345 StatusNoSel: string;
346 StatusSmallSel: string;
347 StatusStreamSel: string;
348 StatusColSel: string;
349 StatusCarets: string;
350 StatusPanels: string;
351 StatusTime: integer;
352 StatusHeightPercents: integer;
353 StatusHeightMin: integer;
354
355 AltTooltipTime: integer;
356 AltTooltipTimeMax: integer;
357 AltTooltipPaddingX: integer;
358 AltTooltipPaddingY: integer;
359
360 ScrollbarWidth: integer;
361 ScrollbarBorderSize: integer;
362 ScrollbarArrowSize: integer;
363
364 ProgressbarWidth: integer;
365 ProgressbarHeightSmall: integer;
366
367 ShowMenubar: boolean;
368 ShowStatusbar: boolean;
369 ShowToolbar: boolean;
370 ShowTitlePath: boolean;
371 Scale: integer;
372 ScaleFont: integer;
373
374 ReopenSession: boolean;
375 ReopenSessionWithCmdLine: boolean;
376 SessionSaveInterval: integer;
377 SessionSaveOnExit: boolean;
378 BackupLastSessions: integer;
379 SaveModifiedTabsOnClose: boolean;
380
381 ShowFormsOnTop: boolean;
382 ShowMenuDialogsWithBorder: boolean;
383 UndoPersistent: string;
384 AllowSaveOfUnmodifiedFile: boolean;
385
386 PluginDialogsShowInTaskbar: boolean;
387 PluginDialogsModalFormStyle: TFormStyle;
388 FloatGroupsShowInTaskbar: TShowInTaskbar;
389 OneInstance: boolean;
390 NotificationEnabled: boolean;
391 NotificationTimeSeconds: integer;
392 NotificationConfirmReload: integer;
393 MarkFilesDeletedOutsideAsModified: boolean;
394 NonTextFiles: integer; //0: prompt, 1: open, 2: don't open
395 NonTextFilesBufferKb: integer;
396 ReloadUnsavedConfirm: boolean;
397 ReloadFollowTail: boolean;
398 CheckLowDiskSpace: Int64; //minimal disk free space in bytes; can be 0 to disable the check
399 FullScreen: string;
400 MouseGotoDefinition: string;
401
402 Emmet_AddSlashToEmptyTags: boolean;
403 Emmet_CommentTags: boolean;
404 Emmet_IndentNested: boolean;
405 Emmet_SingleLine: boolean;
406 Emmet_TrimLineMarkers: boolean;
407 Emmet_WordWrap: boolean;
408
409 HotkeyFindDialog,
410 HotkeyReplaceDialog,
411 HotkeyFindFirst,
412 HotkeyFindNext,
413 HotkeyFindPrev,
414 HotkeyReplaceAndFindNext,
415 HotkeyReplaceNoFindNext,
416 HotkeyReplaceAll,
417 HotkeyReplaceGlobal,
418 HotkeyCountAll,
419 HotkeyExtractAll,
420 HotkeySelectAll,
421 HotkeyMarkAll,
422 HotkeyToggleRegex,
423 HotkeyToggleCaseSens,
424 HotkeyToggleWords,
425 HotkeyToggleWrapped,
426 HotkeyToggleInSelect,
427 HotkeyToggleMultiline,
428 HotkeyToggleConfirmRep,
429 HotkeyToggleTokens,
430 HotkeyToggleHiAll
431 : string;
432 end;
433 var
434 UiOps: TUiOps;
435
436 const
437 OpStr_FontName = 'font_name'+cOptionSystemSuffix;
438 OpStr_FontName_i = 'font_name_i'+cOptionSystemSuffix;
439 OpStr_FontName_b = 'font_name_b'+cOptionSystemSuffix;
440 OpStr_FontName_bi = 'font_name_bi'+cOptionSystemSuffix;
441 OpStr_FontSize = 'font_size'+cOptionSystemSuffix;
442 OpStr_FontSize_i = 'font_size_i'+cOptionSystemSuffix;
443 OpStr_FontSize_b = 'font_size_b'+cOptionSystemSuffix;
444 OpStr_FontSize_bi = 'font_size_bi'+cOptionSystemSuffix;
445 OpStr_FontQuality = 'font_quality'+cOptionSystemSuffix;
446 OpStr_FontLigatures = 'font_ligatures'; //+cOptionSystemSuffix;
447 OpStr_UiFontName = 'ui_font_name'+cOptionSystemSuffix;
448 OpStr_UiFontSize = 'ui_font_size'+cOptionSystemSuffix;
449 OpStr_UiFontOutputName = 'ui_font_output_name'+cOptionSystemSuffix;
450 OpStr_UiFontOutputSize = 'ui_font_output_size'+cOptionSystemSuffix;
451 OpStr_UiFontStatusbarName = 'ui_font_statusbar_name'+cOptionSystemSuffix;
452 OpStr_UiFontStatusbarSize = 'ui_font_statusbar_size'+cOptionSystemSuffix;
453 OpStr_UiDoubleBuffered = 'ui_buffered'+cOptionSystemSuffix;
454 OpStr_DefEncodingIsUtf8 = 'def_encoding_utf8'+cOptionSystemSuffix;
455
456 type
457 TEditorOps = record
458 OpFontName: string;
459 OpFontName_i: string;
460 OpFontName_b: string;
461 OpFontName_bi: string;
462 OpFontSize: integer;
463 OpFontSize_i: integer;
464 OpFontSize_b: integer;
465 OpFontSize_bi: integer;
466 OpFontSize_original: integer;
467 OpFontSize_original_i: integer;
468 OpFontSize_original_b: integer;
469 OpFontSize_original_bi: integer;
470 OpFontQuality: TFontQuality;
471 OpFontLigatures: boolean;
472
473 OpScrollAnimationSteps: integer;
474 OpScrollAnimationSleep: integer;
475
476 OpScrollbarsNew: boolean;
477 OpSpacingY: integer;
478 OpTabSize: integer;
479 OpTabSpaces: boolean;
480 OpMaxLineLenForBracketFinder: integer;
481 OpMaxLineLenToTokenize: integer;
482
483 OpActiveBorderRaw: integer;
484 OpActiveBorderInControls: boolean;
485 OpActiveBorderInEditor: boolean;
486 OpActiveBorderWidth: integer;
487
488 OpOverwriteSel: boolean;
489 OpOverwriteOnPaste: boolean;
490 OpPasteWithEolAtLineStart: boolean;
491
492 OpAutoCloseBracketsMultiCarets: boolean;
493 OpAutoCloseBrackets: string;
494 OpAutocompleteAutoshowCharCount: integer;
495 OpAutocompleteTriggerChars: string;
496 OpAutocompleteCommitChars: string;
497 OpAutocompleteCloseChars: string;
498 OpAutocompleteAddOpeningBracket: boolean;
499 OpAutocompleteUpDownAtEdge: integer;
500 OpAutocompleteCommitIfSingleItem: boolean;
501
502 OpUnderlineColorFiles: string;
503 OpUnderlineColorSize: integer;
504 OpLinks: boolean;
505 OpLinksRegex: string;
506
507 //view
508 OpGutterShow: boolean;
509 OpGutterFold: boolean;
510 OpGutterFoldAlways: boolean;
511 OpGutterFoldIcons: integer;
512 OpGutterBookmarks: boolean;
513
514 OpNumbersShow: boolean;
515 OpNumbersStyle: integer;
516 OpNumbersForCarets: boolean;
517 OpNumbersCenter: boolean;
518
519 OpRulerShow: boolean;
520 OpRulerNumeration: integer;
521 OpRulerMarkCaret: integer;
522
523 OpMinimapShow: boolean;
524 OpMinimapShowSelAlways: boolean;
525 OpMinimapShowSelBorder: boolean;
526 OpMinimapCharWidth: integer;
527 OpMinimapAtLeft: boolean;
528 OpMinimapScale: integer;
529 OpMinimapTooltipShow: boolean;
530 OpMinimapTooltipLineCount: integer;
531 OpMinimapTooltipWidth: integer;
532 OpMinimapDragImmediately: boolean;
533
534 OpMicromapShow: boolean;
535 OpMicromapOnScrollbar: boolean;
536 OpMicromapLineStates: boolean;
537 OpMicromapSelections: boolean;
538 OpMicromapBookmarks: boolean;
539 OpMicromapSmallMarkSizePercents: integer;
540 OpMicromapMinMarkHeight: integer;
541
542 OpMarginFixed: integer;
543 OpMarginString: string;
544
545 OpMarkerSize: integer;
546 OpStaplesStyle: integer;
547 OpStaplesProps: string;
548 OpStapleIndentConsidersEnd: boolean;
549
550 //unprinted
551 OpUnprintedShow: boolean;
552 OpUnprintedContent: string;
553
554 //wrap
555 OpWrapMode: integer;
556 OpWrapIndented: boolean;
557 OpWrapEnabledMaxLines: integer;
558
559 //undo
560 OpUndoLimit: integer;
561 OpUndoGrouped: boolean;
562 OpUndoAfterSave: boolean;
563 OpUndoMaxCarets: integer;
564 OpUndoIndentVert: integer;
565 OpUndoIndentHorz: integer;
566 OpUndoPause: integer;
567 OpUndoMouseClicks: boolean;
568
569 //caret
570 OpCaretBlinkTime: integer;
571 OpCaretBlinkEn: boolean;
572 OpCaretViewNormal: string;
573 OpCaretViewOverwrite: string;
574 OpCaretViewReadonly: string;
575 OpCaretVirtual: boolean;
576 OpCaretMulti: boolean;
577 OpCaretAfterPasteColumn: integer;
578 OpCaretsAddedToColumnSel: boolean;
579 OpCaretsPrimitiveColumnSel: boolean;
580 OpCaretKeepVisibleOnScroll: boolean;
581 OpCaretProximityVert: integer;
582
583 //general
584 OpKeepSelFontColor: boolean;
585 OpShowCurLine: boolean;
586 OpShowCurLineMinimal: boolean;
587 OpShowCurLineOnlyFocused: boolean;
588 OpShowCurCol: boolean;
589 OpShowLastLineOnTop: boolean;
590 OpShowFullBackgroundSel: boolean;
591 OpShowFullBackgroundSyntax: boolean;
592 OpShowMouseSelFrame: boolean;
593 OpCopyLineIfNoSel: boolean;
594 OpCutLineIfNoSel: boolean;
595 OpCopyColumnAlignedBySpaces: boolean;
596 OpSavingTrimSpaces: boolean;
597 OpSavingTrimFinalEmptyLines: boolean;
598 OpSavingForceFinalEol: boolean;
599 OpShowHintOnVertScroll: boolean;
600 OpSmoothScroll: boolean;
601 OpCenteringWidth: integer;
602 OpCenteringForDistractionFree: integer;
603 OpScrollStyleHorz: integer;
604 OpLexerDynamicHiliteEnabled: boolean;
605 OpLexerDynamicHiliteMaxLines: integer;
606 OpLexerLineSeparators: boolean;
607 OpZebra: integer;
608 OpZebraStep: integer;
609 OpDimUnfocused: integer;
610 OpCommandLogMaxCount: integer;
611
612 OpNonWordChars: UnicodeString;
613 OpFoldStyle: integer;
614 OpFoldTooltipShow: boolean;
615
616 //indent
617 OpIndentAuto: boolean;
618 OpIndentAutoKind: integer;
619 OpIndentSize: integer;
620 OpIndentAutoRule: string;
621 OpUnIndentKeepsAlign: boolean;
622 OpIndentMakesWholeLineSel: boolean;
623
624 //mouse
625 OpMouse2ClickDragSelectsWords: boolean;
626 OpMouseDragDrop: boolean;
627 OpMouseMiddleClickAction: integer;
628 OpMouseRightClickMovesCaret: boolean;
629 OpMouseEnableColumnSelection: boolean;
630 OpMouseHideCursorOnType: boolean; //don't work on lin
631 OpMouseGutterClickSelectedLine: boolean;
632 OpMouseWheelZoom: boolean;
633 OpMouseWheelSpeedVert: integer;
634 OpMouseWheelSpeedHorz: integer;
635 OpMouseClickNumberSelectsEol: boolean;
636 OpMouseClickLinks: integer;
637
638 //keys
639 OpKeyBackspaceUnindent: boolean;
640 OpKeyBackspaceWrap: boolean;
641 OpKeyTabIndents: boolean;
642 OpKeyHomeToNonSpace: boolean;
643 OpKeyHomeEndNavigateWrapped: boolean;
644 OpKeyEndToNonSpace: boolean;
645 OpKeyPageKeepsRelativePos: boolean;
646 OpKeyPageUpDownSize: integer;
647 OpKeyUpDownKeepColumn: boolean;
648 OpKeyUpDownNavigateWrapped: boolean;
649 OpKeyUpDownAllowToEdge: boolean;
650 OpKeyLeftRightGoToNextLineWithCarets: boolean;
651 OpKeyLeftRightSwapSel: boolean;
652 OpKeyLeftRightSwapSelAndSelect: boolean;
653
654 OpBracketHilite: boolean;
655 OpBracketSymbols: string;
656 OpBracketDistance: integer;
657 end;
658 var
659 EditorOps: TEditorOps;
660
661 var
662 AppDir_Home: string;
663 AppDir_Settings: string;
664 AppDir_SettingsDefault: string;
665 AppDir_Py: string;
666 AppDir_Data: string;
667 AppDir_Lexers: string;
668 AppDir_LexersLite: string;
669 AppDir_DataThemes: string;
670 AppDir_DataAutocomplete: string;
671 AppDir_DataAutocompleteSpec: string;
672 AppDir_DataLang: string;
673 AppDir_DataSidebarIcons: string;
674 AppDir_DataCodetreeIcons: string;
675 AppDir_DataToolbarIcons: string;
676 AppDir_LastInstalledAddon: string = '';
677 AppFile_OptionsDefault: string;
678 AppFile_OptionsUserInit: string;
679 AppFile_OptionsUser: string;
680 AppFile_History: string;
681 AppFile_HistoryFiles: string;
682 AppFile_Hotkeys: string;
683 AppFile_PluginsIni: string;
684
GetAppLangFilenamenull685 function GetAppLangFilename: string;
GetAppUndoFilenamenull686 function GetAppUndoFilename(const fn: string; IsRedo: boolean): string;
687
EscapeLexerFilenamenull688 function EscapeLexerFilename(const ALexName: string): string;
GetAppLexerFilenamenull689 function GetAppLexerFilename(const ALexName: string): string;
GetAppLexerMapFilenamenull690 function GetAppLexerMapFilename(const ALexName: string): string;
GetAppLexerOpsFilenamenull691 function GetAppLexerOpsFilename(const ALexName: string): string;
GetAppLexerAcpFilenamenull692 function GetAppLexerAcpFilename(const ALexName: string): string;
GetAppLexerSpecificConfignull693 function GetAppLexerSpecificConfig(ALexer: string; ADefaultConfig: boolean=false): string;
GetAppFilenameIsIgnoredForSessionnull694 function GetAppFilenameIsIgnoredForSession(const AFilename: string): boolean;
IsDefaultSessionActivenull695 function IsDefaultSessionActive: boolean;
696
MsgBoxnull697 function MsgBox(const Str: string; Flags: Longint): integer;
698 procedure MsgBadConfig(const fn, msg: string);
699 procedure MsgStdout(const Str: string; AllowMsgBox: boolean = false);
700 procedure MsgLogConsole(const AText: string);
701
AppScalenull702 function AppScale(AValue: integer): integer;
AppScaleFontnull703 function AppScaleFont(AValue: integer): integer;
704 //procedure AppScaleScrollbar(C: TATScroll);
AppListboxItemHeightnull705 function AppListboxItemHeight(AScale, ADoubleHeight: boolean): integer;
706 procedure AppGetFileProps(const FileName: string; out P: TAppFileProps);
707 procedure AppUpdateWatcherFrames;
708
709 procedure FixFormPositionToDesktop(F: TForm);
710 procedure FixRectPositionToDesktop(var F: TRect);
711
712 type
713 { TKeymapHelper }
714
715 TKeymapHelper = class
716 public
717 class procedure ClearKey(AKeymap: TATKeymap; AItemIndex, AKeyIndex: integer);
718 class procedure ClearKeyInAll(AItemIndex, AKeyIndex: integer);
719
GetHotkeynull720 class function GetHotkey(AKeymap: TATKeymap; const ACmdString: string): string;
SetHotkeynull721 class function SetHotkey(AKeymap: TATKeymap; const AParams: string; AndSaveFile: boolean): boolean;
722
CheckDuplicateForCommandnull723 class function CheckDuplicateForCommand(
724 AKeymapItem: TATKeymapItem;
725 const ALexerName: string;
726 AOverwriteAndSave: boolean): integer;
727
GetForLexernull728 class function GetForLexer(const ALexer: string): TATKeymap;
729 class procedure LoadConfig(AKeymap: TATKeymap; const AFileName: string; AForLexer: boolean);
730
731 class procedure ItemSaveToConfig(K: TATKeymapItem; const path, ALexerName: string; ALexerSpecific: boolean);
732 class procedure ItemDeleteInConfig(K: TATKeymapItem; const path, ALexerName: string; ALexerSpecific: boolean);
733
SaveKey_ForPluginnull734 class function SaveKey_ForPlugin(AKeymap: TATKeymap; AOverwriteKey: boolean;
735 const AMenuitemCaption, AModuleName, AMethodName, ALexerName, AHotkey: string): boolean;
736 end;
737
DoLexerDetectByFilenameOrContentnull738 function DoLexerDetectByFilenameOrContent(const AFilename: string;
739 AChooseFunc: TecLexerChooseFunc): TecSyntAnalyzer;
740 procedure DoLexerEnum(L: TStringList; AlsoDisabled: boolean = false);
741
DoReadOneStringFromFilenull742 function DoReadOneStringFromFile(const AFilename: string): string;
DoReadContentFromFilenull743 function DoReadContentFromFile(const AFilename: string): string;
744 procedure DoWriteStringToFile(const AFilename, AText: string);
745
AppCollapseHomeDirInFilenamenull746 function AppCollapseHomeDirInFilename(const fn: string): string;
AppExpandHomeDirInFilenamenull747 function AppExpandHomeDirInFilename(const fn: string): string;
AppExpandFileNameWithDirnull748 function AppExpandFileNameWithDir(const AFileName, ADir: string): string;
AppConfigKeyForBookmarksnull749 function AppConfigKeyForBookmarks(Ed: TATSynEdit): string;
750 procedure AppDiskCheckFreeSpace(const fn: string);
AppKeyIsAllowedAsCustomHotkeynull751 function AppKeyIsAllowedAsCustomHotkey(Key: Word; Shift: TShiftState): boolean;
752
753 var
754 AppManager: TecLexerList = nil;
755 AppManagerLite: TATLiteLexers = nil;
756 AppShortcutEscape: TShortcut = 0;
757 AppShortcutShiftTab: TShortcut = 0;
758
759 AppKeymapMain: TATKeymap = nil;
760 AppKeymapInitial: TATKeymap = nil; //inited only by API calls
761 AppKeymapLexers: TStringList = nil;
762
763 type
764 TStrEvent = procedure(Sender: TObject; const ARes: string) of object;
765 TStrFunction = function(const AStr: string): boolean of object;
766
767 type
768 TAppEncodingRecord = record
769 Sub,
770 Name,
771 ShortName: string;
772 end;
773
774 const
775 AppEncodings: array[0..38] of TAppEncodingRecord = (
776 (Sub: ''; Name: cEncNameUtf8_NoBom; ShortName: 'utf8'),
777 (Sub: ''; Name: cEncNameUtf8_WithBom; ShortName: 'utf8_bom'),
778 (Sub: ''; Name: cEncNameUtf16LE_NoBom; ShortName: 'utf16le'),
779 (Sub: ''; Name: cEncNameUtf16LE_WithBom; ShortName: 'utf16le_bom'),
780 (Sub: ''; Name: cEncNameUtf16BE_NoBom; ShortName: 'utf16be'),
781 (Sub: ''; Name: cEncNameUtf16BE_WithBom; ShortName: 'utf16be_bom'),
782 (Sub: ''; Name: cEncNameUtf32LE_NoBom; ShortName: 'utf32le'),
783 (Sub: ''; Name: cEncNameUtf32LE_WithBom; ShortName: 'utf32le_bom'),
784 (Sub: ''; Name: cEncNameUtf32BE_NoBom; ShortName: 'utf32be'),
785 (Sub: ''; Name: cEncNameUtf32BE_WithBom; ShortName: 'utf32be_bom'),
786 (Sub: ''; Name: '-'; ShortName: ''),
787 (Sub: 'eu'; Name: 'cp1250'; ShortName: 'cp1250'),
788 (Sub: 'eu'; Name: 'cp1251'; ShortName: 'cp1251'),
789 (Sub: 'eu'; Name: 'cp1252'; ShortName: 'cp1252'),
790 (Sub: 'eu'; Name: 'cp1253'; ShortName: 'cp1253'),
791 (Sub: 'eu'; Name: 'cp1257'; ShortName: 'cp1257'),
792 (Sub: 'eu'; Name: '-'; ShortName: ''),
793 (Sub: 'eu'; Name: 'cp437'; ShortName: 'cp437'),
794 (Sub: 'eu'; Name: 'cp850'; ShortName: 'cp850'),
795 (Sub: 'eu'; Name: 'cp852'; ShortName: 'cp852'),
796 (Sub: 'eu'; Name: 'cp866'; ShortName: 'cp866'),
797 (Sub: 'eu'; Name: '-'; ShortName: ''),
798 (Sub: 'eu'; Name: 'iso88591'; ShortName: 'iso88591'),
799 (Sub: 'eu'; Name: 'iso88592'; ShortName: 'iso88592'),
800 (Sub: 'eu'; Name: 'iso885915'; ShortName: 'iso885915'),
801 (Sub: 'eu'; Name: 'mac'; ShortName: 'mac'),
802 (Sub: 'mi'; Name: 'cp1254'; ShortName: 'cp1254'),
803 (Sub: 'mi'; Name: 'cp1255'; ShortName: 'cp1255'),
804 (Sub: 'mi'; Name: 'cp1256'; ShortName: 'cp1256'),
805 (Sub: 'mi'; Name: '-'; ShortName: ''),
806 (Sub: 'mi'; Name: 'koi8r'; ShortName: 'koi8r'),
807 (Sub: 'mi'; Name: 'koi8u'; ShortName: 'koi8u'),
808 (Sub: 'mi'; Name: 'koi8ru'; ShortName: 'koi8ru'),
809 (Sub: 'as'; Name: 'cp874'; ShortName: 'cp874'),
810 (Sub: 'as'; Name: 'cp932'; ShortName: 'cp932'),
811 (Sub: 'as'; Name: 'cp936'; ShortName: 'cp936'),
812 (Sub: 'as'; Name: 'cp949'; ShortName: 'cp949'),
813 (Sub: 'as'; Name: 'cp950'; ShortName: 'cp950'),
814 (Sub: 'as'; Name: 'cp1258'; ShortName: 'cp1258')
815 );
816
817 type
818 TAppPyEventResult = record
819 Val: (evrTrue, evrFalse, evrInt, evrString, evrOther);
820 Int: integer;
821 Str: string;
822 end;
823
824 type
825 TAppPyEvent = (
826 cEventOnKey,
827 cEventOnKeyUp,
828 cEventOnHotspot,
829 cEventOnInsert,
830 cEventOnChange,
831 cEventOnChangeSlow,
832 cEventOnCaret,
833 cEventOnScroll,
834 cEventOnMouseStop,
835 cEventOnClick,
836 cEventOnClickDbl,
837 cEventOnClickGutter,
838 cEventOnClickGap,
839 cEventOnClickLink,
840 cEventOnState,
841 cEventOnStateEd,
842 cEventOnFocus,
843 cEventOnStart,
844 cEventOnOpen,
845 cEventOnOpenBefore,
846 cEventOnOpenNone,
847 cEventOnClose,
848 cEventOnCloseBefore,
849 cEventOnSaveAfter,
850 cEventOnSaveBefore,
851 cEventOnSaveNaming,
852 cEventOnLexer,
853 cEventOnLexerParsed,
854 cEventOnComplete,
855 cEventOnGotoDef,
856 cEventOnGotoEnter,
857 cEventOnFuncHint,
858 cEventOnTabChange,
859 cEventOnTabMove,
860 cEventOnPaste,
861 cEventOnMessage,
862 cEventOnConsoleNav,
863 cEventOnOutputNav,
864 cEventOnSnippet,
865 cEventOnMacro,
866 cEventOnAppActivate,
867 cEventOnAppDeactivate,
868 cEventOnCLI,
869 cEventOnExit
870 );
871 TAppPyEvents = set of TAppPyEvent;
872 TAppPyEventsPrior = array[TAppPyEvent] of byte;
873 //0: default, 1,2...: higher priority
874 TAppPyEventsLazy = array[TAppPyEvent] of boolean;
875
876 var
877 AppEventsMaxPriorities: array[TAppPyEvent] of integer;
878
879 const
880 cAppPyEvent: array[TAppPyEvent] of string = (
881 'on_key',
882 'on_key_up',
883 'on_hotspot',
884 'on_insert',
885 'on_change',
886 'on_change_slow',
887 'on_caret',
888 'on_scroll',
889 'on_mouse_stop',
890 'on_click',
891 'on_click_dbl',
892 'on_click_gutter',
893 'on_click_gap',
894 'on_click_link',
895 'on_state',
896 'on_state_ed',
897 'on_focus',
898 'on_start',
899 'on_open',
900 'on_open_pre',
901 'on_open_none',
902 'on_close',
903 'on_close_pre',
904 'on_save',
905 'on_save_pre',
906 'on_save_naming',
907 'on_lexer',
908 'on_lexer_parsed',
909 'on_complete',
910 'on_goto_def',
911 'on_goto_enter',
912 'on_func_hint',
913 'on_tab_change',
914 'on_tab_move',
915 'on_paste',
916 'on_message',
917 'on_console_nav',
918 'on_output_nav',
919 'on_snippet',
920 'on_macro',
921 'on_app_activate',
922 'on_app_deactivate',
923 'on_cli',
924 'on_exit'
925 );
926
927 type
928
929 { TAppCommandInfo }
930
931 TAppCommandInfo = class
932 public
933 ItemModule: string;
934 ItemProc: string;
935 ItemProcParam: string;
936 ItemCaption: string;
937 ItemLexers: string;
938 ItemInMenu: string;
939 ItemFromApi: boolean;
CommaStrnull940 function CommaStr: string;
941 end;
942
943 type
944 TAppEventInfo = class
945 ItemModule: string;
946 ItemLexers: string;
947 ItemEvents: TAppPyEvents;
948 ItemEventsPrior: TAppPyEventsPrior;
949 ItemEventsLazy: TAppPyEventsLazy;
950 ItemKeys: string;
951 end;
952
953 type
954 TAppTreeHelper = class
955 ItemModule: string;
956 ItemProc: string;
957 ItemLexers: string;
958 end;
959
960 var
961 AppConsoleQueue: TAppConsoleQueue;
962 AppCommandsDelayed: TAppCommandsDelayed;
963 AppCommandList: TFPList;
964 AppEventList: TFPList;
965 AppTreeHelpers: TFPList;
966
967 type
968 TAppMenuProps = class
969 public
970 CommandCode: integer;
971 CommandString: string;
972 TagString: string;
973 end;
974
975 type
976 { TPluginHelper }
977
978 TPluginHelper = class
979 public
CommandCategorynull980 class function CommandCategory(Cmd: integer): TAppCommandCategory;
CommandHasConfigurableHotkeynull981 class function CommandHasConfigurableHotkey(Cmd: integer): boolean;
982 class procedure CommandsClearButKeepApiItems;
CommandGetIndexFromModuleAndMethodnull983 class function CommandGetIndexFromModuleAndMethod(const AText: string): integer;
984 class procedure CommandUpdateSubcommands(const AText: string);
985
EventIsUsednull986 class function EventIsUsed(AEvent: TAppPyEvent): boolean;
987 class procedure EventStringToEventData(const AEventStr: string;
988 out AEvents: TAppPyEvents;
989 out AEventsPrior: TAppPyEventsPrior;
990 out AEventsLazy: TAppPyEventsLazy);
991 class procedure EventsUpdate(const AModuleName, AEventStr, ALexerStr, AKeyStr: string);
992 class procedure EventsMaxPrioritiesUpdate;
993
CommandCode_To_HotkeyStringIdnull994 class function CommandCode_To_HotkeyStringId(ACmd: integer): string;
HotkeyStringId_To_CommandCodenull995 class function HotkeyStringId_To_CommandCode(const AId: string): integer;
996
Debug_PluginCommandsnull997 class function Debug_PluginCommands(const AModule: string): string;
998 end;
999
1000
AppEncodingShortnameToFullnamenull1001 function AppEncodingShortnameToFullname(const S: string): string;
AppEncodingFullnameToShortnamenull1002 function AppEncodingFullnameToShortname(const S: string): string;
AppEncodingListAsStringnull1003 function AppEncodingListAsString: string;
1004
1005 procedure UpdateFormOnTop(F: TForm);
1006
1007 procedure DoStatusbarTextByTag(AStatus: TATStatus; ATag: PtrInt; const AText: string);
1008 procedure DoStatusbarHintByTag(AStatus: TATStatus; ATag: PtrInt; const AText: string);
1009 procedure DoStatusbarColorByTag(AStatus: TATStatus; ATag: PtrInt; AColor: TColor);
1010
IsFileTooBigForOpeningnull1011 function IsFileTooBigForOpening(const AFilename: string): boolean;
IsFileTooBigForLexernull1012 function IsFileTooBigForLexer(const AFilename: string): boolean;
IsOsFullPathnull1013 function IsOsFullPath(const S: string): boolean;
1014 procedure DoLexerDetect(const AFilename: string;
1015 out Lexer: TecSyntAnalyzer;
1016 out LexerLite: TATLiteLexer;
1017 out LexerName: string;
1018 AChooseFunc: TecLexerChooseFunc);
1019 procedure DoMenuitemEllipsis(c: TMenuItem);
1020
1021 procedure AppOnLexerLoaded(Sender: TObject; ALexer: TecSyntAnalyzer);
1022 procedure AppLoadLexers;
1023
1024 type
1025 { TAppManagerThread }
1026
1027 TAppManagerThread = class(TThread)
1028 public
1029 procedure Execute; override;
1030 end;
1031
1032 var
1033 AppManagerThread: TAppManagerThread = nil;
1034
1035 implementation
1036
1037 uses
1038 ATSynEdit_LineParts,
1039 ATSynEdit_Adapter_EControl,
1040 ec_syntax_format,
1041 proc_colors,
1042 proc_lexer_styles;
1043
MsgBoxnull1044 function MsgBox(const Str: string; Flags: Longint): integer;
1045 begin
1046 Result:= Application.MessageBox(PChar(Str), PChar(msgTitle), Flags);
1047 end;
1048
1049 procedure MsgBadConfig(const fn, msg: string);
1050 begin
1051 //MsgBox(msgCannotReadConfig+#10+fn+#10#10+msg, MB_OK+MB_ICONERROR);
1052 MsgLogConsole('ERROR: '+msgCannotReadConfig+' '+ExtractFileName(fn)+'; '+msg);
1053 end;
1054
InitPyLibraryPathnull1055 function InitPyLibraryPath: string;
1056 const
1057 cMaxVersion = 10;
1058 cMinVersionUnix = 5;
1059 cMinVersionWindows = 4; //support Python 3.4 for WinXP
1060 {$ifdef windows}
1061 var
1062 N: integer;
1063 S, SFile: string;
1064 {$endif}
1065 {$ifdef darwin}
1066 var
1067 N: integer;
1068 S: string;
1069 {$endif}
1070 begin
1071 Result:= '';
1072
1073 {$ifdef windows}
1074 //detect latest existing file python3x.dll in app folder
1075 S:= ExtractFilePath(Application.ExeName);
1076 for N:= cMaxVersion downto cMinVersionWindows do
1077 begin
1078 SFile:= Format('python3%d.dll', [N]);
1079 //don't return full filename, this loads DLL with full filename and plugins cannot load
1080 if FileExists(S+SFile) then
1081 exit(SFile);
1082 end;
1083 exit;
1084 {$endif}
1085
1086 {$ifdef darwin}
1087 for N:= cMaxVersion downto cMinVersionUnix do
1088 begin
1089 S:= Format('/Library/Frameworks/Python.framework/Versions/3.%d/lib/libpython3.%d.dylib',
1090 [N, N]);
1091 if FileExists(S) then exit(S);
1092 end;
1093 exit;
1094 {$endif}
1095
1096 {$ifdef dragonfly}
1097 exit('/usr/local/lib/libpython3.6m.so');
1098 {$endif}
1099
1100 {$ifdef netbsd}
1101 exit('/usr/pkg/lib/libpython3.7.so');
1102 {$endif}
1103
1104 {$ifdef solaris}
1105 exit('/usr/lib/amd64/libpython3.5m.so');
1106 {$endif}
1107
1108 {$ifdef haiku}
1109 exit('/boot/system/develop/lib/libpython3.6m.so');
1110 {$endif}
1111
1112 {$ifdef unix}
1113 exit('libpython3.so');
1114 {$endif}
1115 end;
1116
1117 var
1118 OpFileExe: string = '';
1119 OpDirExe: string = '';
1120 OpDirLocal: string = '';
1121 OpDirPrecopy: string = '';
1122
1123 function GetDirPrecopy: string;
1124 begin
1125 {$ifdef linux}
1126 exit('/usr/share/cudatext');
1127 {$endif}
1128
1129 {$ifdef darwin}
1130 exit(ExtractFileDir(OpDirExe)+'/Resources');
1131 {$endif}
1132
1133 {$ifdef dragonfly}
1134 exit('/usr/local/share/cudatext');
1135 {$endif}
1136
1137 Result:= '';
1138 end;
1139
1140 function AppCollapseHomeDirInFilename(const fn: string): string;
1141 {$ifndef windows}
1142 var
1143 S: string;
1144 {$endif}
1145 begin
1146 Result:= fn;
1147 {$ifndef windows}
1148 S:= AppDir_Home;
1149 if SBeginsWith(Result, S) then
1150 Result:= '~'+DirectorySeparator+Copy(Result, Length(S)+1, MaxInt);
1151 {$endif}
1152 end;
1153
1154 function AppExpandHomeDirInFilename(const fn: string): string;
1155 begin
1156 Result:= fn;
1157 {$ifndef windows}
1158 if SBeginsWith(Result, '~'+DirectorySeparator) then
1159 Result:= AppDir_Home+Copy(Result, 3, MaxInt);
1160 {$endif}
1161 end;
1162
1163 function AppExpandFileNameWithDir(const AFileName, ADir: string): string;
1164 var
1165 S: string;
1166 begin
1167 S:= GetCurrentDir;
1168 SetCurrentDir(ADir);
1169 Result:= ExpandFileName(AFileName);
1170 SetCurrentDir(S);
1171 end;
1172
1173
1174 function IsDistroUpdateNeeded: boolean;
1175 begin
1176 with TIniFile.Create(AppDir_Settings+DirectorySeparator+'packages.ini') do
1177 try
1178 Result:= ReadString('app', 'ver', '')<>cAppExeVersion;
1179 if Result then
1180 WriteString('app', 'ver', cAppExeVersion);
1181 finally
1182 Free
1183 end;
1184 end;
1185
1186 function AppDirSettingsFromCommandLine: string;
1187 const
1188 cParam = '-s=';
1189 var
1190 S: string;
1191 i: integer;
1192 begin
1193 Result:= '';
1194 for i:= 1{not 0} to ParamCount do
1195 begin
1196 S:= ParamStr(i);
1197 if SBeginsWith(S, cParam) then
1198 begin
1199 Delete(S, 1, Length(cParam));
1200 exit(AppExpandHomeDirInFilename(S));
1201 end;
1202 end;
1203 end;
1204
1205 function Which(const Executable: string): string;
1206 var
1207 ExeName,FoundExe:string;
1208 //Output: string;
1209 begin
1210 result:='';
1211
1212 ExeName:=Executable;
1213
1214 {$ifdef Windows}
1215 if ExtractFileExt(ExeName)='' then ExeName:=ExeName+'.exe';
1216 {$endif}
1217 {$ifdef dragonfly}
1218 OpDirLocal:= AppDir_Home + '.config/' + 'cudatext';
1219 CreateDirUTF8(OpDirLocal);
1220 {$endif}
1221
1222 if FileExists(ExeName) then
1223 exit(ExeName)
1224 else
1225 begin
1226 FoundExe := ExeSearch(ExeName, '');
1227 if FileExists(FoundExe) then
1228 result:=FoundExe
1229 else
1230 result:=FindDefaultExecutablePath(ExeName);
1231 end;
1232
1233 (*
1234 {$IFNDEF FREEBSD}
1235 if (NOT FileIsExecutable(result)) then result:='';
1236 {$ENDIF}
1237 *)
1238
1239 (*
1240 {$IFDEF UNIX}
1241 if (NOT FileExists(result)) then
1242 begin
1243 RunCommand('which',[ExeName],Output,[poUsePipes, poStderrToOutPut]{$IF DEFINED(FPC_FULLVERSION) AND (FPC_FULLVERSION >= 30200)},swoHide{$ENDIF});
1244 Output:=Trim(Output);
1245 if ((Output<>'') and FileExists(Output)) then result:=Output;
1246 end;
1247 {$ENDIF}
1248 *)
1249 end;
1250
1251 procedure InitDirs_Windows;
1252 begin
1253 AppDir_Home:= '';
1254 end;
1255
1256 procedure InitDirs_macOS;
1257 begin
1258 //from https://github.com/graemeg/freepascal/blob/master/rtl/unix/sysutils.pp
1259 AppDir_Home:= GetEnvironmentVariable('HOME');
1260 if AppDir_Home<>'' then
1261 AppDir_Home:= IncludeTrailingPathDelimiter(AppDir_Home);
1262 OpDirLocal:= AppDir_Home+'Library/Application Support/CudaText';
1263 CreateDirUTF8(OpDirLocal);
1264 end;
1265
1266 procedure InitDirs_Haiku;
1267 var
1268 HomeConfig: string;
1269 begin
1270 AppDir_Home:= '/boot/home';
1271 HomeConfig:= AppDir_Home+'/config/settings';
1272 OpDirLocal:= HomeConfig+'/cudatext';
1273 CreateDirUTF8(OpDirLocal);
1274 end;
1275
1276 procedure InitDirs_UnixCommon;
1277 var
1278 HomeConfig: string;
1279 SPathOrig, SPath: RawByteString;
1280 bAppPortable: boolean;
1281 begin
1282 //from https://github.com/graemeg/freepascal/blob/master/rtl/unix/sysutils.pp
1283 AppDir_Home:= GetEnvironmentVariable('HOME');
1284 if AppDir_Home<>'' then
1285 AppDir_Home:= IncludeTrailingPathDelimiter(AppDir_Home);
1286
1287 SPathOrig:= Which(OpFileExe);
1288 //MsgStdout('CudaText binary: '+SPathOrig);
1289 {$if FPC_FULLVERSION>30200}
1290 //FileGetSymLinkTarget was added in FPC 3.2
1291 if FileGetSymLinkTarget(SPathOrig, SPath) then
1292 begin
1293 //support relative target of symlink like '../dir/cudatext'
1294 if not SBeginsWith(SPath, '/') then
1295 SPath:= ExtractFilePath(SPathOrig)+SPath;
1296 MsgStdout('CudaText starts via symlink to: '+SPath);
1297 OpDirLocal:= ExtractFileDir(SPath);
1298 end
1299 else
1300 {$endif}
1301 begin
1302 bAppPortable:= DirectoryExists(OpDirExe+'/data/lexlib') and
1303 not SBeginsWith(OpDirExe, '/opt/');
1304 if not bAppPortable then
1305 begin
1306 HomeConfig:= GetEnvironmentVariable('XDG_CONFIG_HOME');
1307 if HomeConfig='' then
1308 HomeConfig:= AppDir_Home + '.config/'
1309 else
1310 HomeConfig:= IncludeTrailingPathDelimiter(HomeConfig);
1311
1312 OpDirLocal:= HomeConfig+'cudatext';
1313 CreateDirUTF8(OpDirLocal);
1314 //MsgStdout('CudaText starts not portable: '+OpDirLocal);
1315 end;
1316 end;
1317 end;
1318
1319 procedure InitDirs;
1320 var
1321 S: string;
1322 begin
1323 OpFileExe:= ParamStr(0);
1324 OpDirExe:= ExtractFileDir(OpFileExe);
1325 OpDirPrecopy:= GetDirPrecopy;
1326 OpDirLocal:= OpDirExe;
1327
1328 {$ifdef windows}
1329 InitDirs_Windows;
1330 {$else}
1331 {$ifdef darwin}
1332 InitDirs_macOS;
1333 {$else}
1334 {$ifdef haiku}
1335 InitDirs_Haiku;
1336 {$else}
1337 InitDirs_UnixCommon;
1338 {$endif}
1339 {$endif}
1340 {$endif}
1341
1342 //support command line key -s=folder
1343 AppDir_Settings:= AppDirSettingsFromCommandLine;
1344 if AppDir_Settings='' then
1345 AppDir_Settings:= OpDirLocal+DirectorySeparator+'settings';
1346
1347 if not DirectoryExistsUTF8(AppDir_Settings) then
1348 if not CreateDirUTF8(AppDir_Settings) then
1349 begin
1350 MsgStdout(msgCannotCreateDir+' '+AppDir_Settings, true);
1351 Halt;
1352 end;
1353
1354 AppDir_SettingsDefault:= OpDirLocal+DirectorySeparator+'settings_default';
1355
1356 {$ifdef linux}
1357 if OpDirLocal<>OpDirExe then
1358 if IsDistroUpdateNeeded then
1359 if DirectoryExistsUTF8(OpDirPrecopy) then
1360 begin
1361 RunCommand('cp', ['-R', '-u', '-t',
1362 OpDirLocal,
1363 '/usr/share/cudatext/py',
1364 '/usr/share/cudatext/data',
1365 '/usr/share/cudatext/settings_default'
1366 ], S);
1367 //set permissions +w for dir+subdirs
1368 RunCommand('chmod', ['-R', '+w', OpDirLocal], S);
1369 end;
1370 {$endif}
1371 {$ifdef darwin}
1372 if IsDistroUpdateNeeded then
1373 if DirectoryExistsUTF8(OpDirPrecopy) then
1374 //see rsync help. need options:
1375 // -u (update)
1376 // -r (recursive)
1377 // -t (preserve times)
1378 RunCommand('rsync', ['-urt',
1379 OpDirPrecopy+'/',
1380 OpDirLocal
1381 ], S);
1382 {$endif}
1383 {$ifdef dragonfly}
1384 RunCommand('cp', ['-R',
1385 '/usr/local/share/cudatext/py',
1386 '/usr/local/share/cudatext/data',
1387 '/usr/local/share/cudatext/readme',
1388 '/usr/local/share/cudatext/settings_default',
1389 OpDirLocal
1390 ], S);
1391 {$endif}
1392
1393 AppDir_Py:= OpDirLocal+DirectorySeparator+'py';
1394 AppDir_Data:= OpDirLocal+DirectorySeparator+'data';
1395 AppDir_Lexers:= AppDir_Data+DirectorySeparator+'lexlib';
1396 AppDir_LexersLite:= AppDir_Data+DirectorySeparator+'lexliblite';
1397 AppDir_DataThemes:= AppDir_Data+DirectorySeparator+'themes';
1398 AppDir_DataAutocomplete:= AppDir_Data+DirectorySeparator+'autocomplete';
1399 AppDir_DataAutocompleteSpec:= AppDir_Data+DirectorySeparator+'autocompletespec';
1400 AppDir_DataLang:= AppDir_Data+DirectorySeparator+'lang';
1401 AppDir_DataSidebarIcons:= AppDir_Data+DirectorySeparator+'sideicons';
1402 AppDir_DataCodetreeIcons:= AppDir_Data+DirectorySeparator+'codetreeicons';
1403 AppDir_DataToolbarIcons:= AppDir_Data+DirectorySeparator+'toolbaricons';
1404 AppFile_OptionsDefault:= AppDir_SettingsDefault+DirectorySeparator+'default.json';
1405 AppFile_OptionsUserInit:= AppDir_SettingsDefault+DirectorySeparator+'userinit.json';
1406 AppFile_OptionsUser:= AppDir_Settings+DirectorySeparator+'user.json';
1407 AppFile_History:= AppDir_Settings+DirectorySeparator+'history.json';
1408 AppFile_HistoryFiles:= AppDir_Settings+DirectorySeparator+'history files.json';
1409 AppFile_Hotkeys:= AppDir_Settings+DirectorySeparator+'keys.json';
1410 AppFile_PluginsIni:= AppDir_Settings+DirectorySeparator+'plugins.ini';
1411
1412 if not FileExists(AppFile_OptionsUser)
1413 and FileExists(AppFile_OptionsUserInit) then
1414 CopyFile(AppFile_OptionsUserInit, AppFile_OptionsUser, [], false);
1415 end;
1416
1417 const
1418 AppDefaultEdFont: string = '';
1419 AppDefaultEdFonts: array[0..2] of string =
1420 {$ifdef windows}
1421 ('Consolas', 'Courier New', 'Courier');
1422 {$else}
1423 {$ifdef darwin}
1424 ('Monaco', 'Liberation Mono', 'DejaVu Sans Mono');
1425 {$else}
1426 {$ifdef haiku}
1427 ('Noto', 'Monoid Nerd', '');
1428 {$else}
1429 ('DejaVu Sans Mono', 'Liberation Mono', 'Courier New');
1430 {$endif}
1431 {$endif}
1432 {$endif}
1433
1434 function InitAppDefaultEdFont: string;
1435 var
1436 i: integer;
1437 begin
1438 for i:= 0 to High(AppDefaultEdFonts) do
1439 begin
1440 Result:= AppDefaultEdFonts[i];
1441 if Screen.Fonts.IndexOf(Result)>=0 then exit;
1442 end;
1443 end;
1444
1445 procedure InitEditorOps(var Op: TEditorOps);
1446 begin
1447 if AppDefaultEdFont='' then
1448 AppDefaultEdFont:= InitAppDefaultEdFont;
1449
1450 with Op do
1451 begin
1452 OpFontName:= AppDefaultEdFont;
1453 OpFontName_i:= '';
1454 OpFontName_b:= '';
1455 OpFontName_bi:= '';
1456
1457 OpFontSize:= 9;
1458 OpFontSize_i:= OpFontSize;
1459 OpFontSize_b:= OpFontSize;
1460 OpFontSize_bi:= OpFontSize;
1461 OpFontSize_original:= OpFontSize;
1462 OpFontSize_original_i:= OpFontSize;
1463 OpFontSize_original_b:= OpFontSize;
1464 OpFontSize_original_bi:= OpFontSize;
1465
1466 OpFontQuality:= fqDefault;
1467 OpFontLigatures:= true;
1468
1469 OpScrollAnimationSteps:= cInitScrollAnimationSteps;
1470 OpScrollAnimationSleep:= cInitScrollAnimationSleep;
1471
1472 OpScrollbarsNew:= true;
1473 OpSpacingY:= 1;
1474
1475 OpTabSize:= 4;
1476 OpTabSpaces:= false;
1477 OpMaxLineLenToTokenize:= 4000;
1478 OpMaxLineLenForBracketFinder:= 1000;
1479
1480 OpActiveBorderRaw:= 1;
1481 OpActiveBorderInControls:= true;
1482 OpActiveBorderInEditor:= false;
1483 OpActiveBorderWidth:= 1;
1484
1485 OpOverwriteSel:= true;
1486 OpOverwriteOnPaste:= false;
1487 OpPasteWithEolAtLineStart:= false; //maybe change it later to True (like Sublime, VSCode)
1488
1489 OpAutoCloseBracketsMultiCarets:= true; //must be True, issue #3235
1490 OpAutoCloseBrackets:= '([{';
1491 OpAutocompleteAutoshowCharCount:= 0;
1492 OpAutocompleteTriggerChars:= '';
1493 OpAutocompleteCommitChars:= ' ,;/\''"';
1494 OpAutocompleteCloseChars:= '<>()[]{}=';
1495 OpAutocompleteAddOpeningBracket:= true;
1496 OpAutocompleteUpDownAtEdge:= 1; //cudWrap
1497 OpAutocompleteCommitIfSingleItem:= false;
1498
1499 OpUnderlineColorFiles:= '*';
1500 OpUnderlineColorSize:= 3;
1501 OpLinks:= true;
1502 OpLinksRegex:= ATSynEdit.cUrlRegexInitial;
1503
1504 OpGutterShow:= true;
1505 OpGutterFold:= true;
1506 OpGutterFoldAlways:= true;
1507 OpGutterBookmarks:= true;
1508 OpGutterFoldIcons:= 0;
1509
1510 OpNumbersShow:= true;
1511 OpNumbersStyle:= Ord(cNumbersAll);
1512 OpNumbersForCarets:= false;
1513 OpNumbersCenter:= true;
1514
1515 OpRulerShow:= false;
1516 OpRulerNumeration:= 0;
1517 OpRulerMarkCaret:= 1;
1518
1519 OpMinimapShow:= false;
1520 OpMinimapShowSelAlways:= false;
1521 OpMinimapShowSelBorder:= true;
1522 OpMinimapCharWidth:= 0;
1523 OpMinimapAtLeft:= false;
1524 OpMinimapScale:= 0;
1525 OpMinimapTooltipShow:= false;
1526 OpMinimapTooltipLineCount:= 6;
1527 OpMinimapTooltipWidth:= 60;
1528 OpMinimapDragImmediately:= false;
1529
1530 OpMicromapShow:= false;
1531 OpMicromapOnScrollbar:= false;
1532 OpMicromapLineStates:= true;
1533 OpMicromapSelections:= true;
1534 OpMicromapBookmarks:= false;
1535 OpMicromapSmallMarkSizePercents:= 50;
1536 OpMicromapMinMarkHeight:= 4;
1537
1538 OpMarginFixed:= 2000; //hide margin
1539 OpMarginString:= '';
1540
1541 OpMarkerSize:= 30;
1542 OpStaplesStyle:= 1; //Ord(cLineStyleSolid)
1543 OpStaplesProps:= '-1,40,1,1';
1544 OpStapleIndentConsidersEnd:= true;
1545
1546 OpUnprintedShow:= false;
1547 OpUnprintedContent:= 'se';
1548
1549 OpWrapMode:= 0;
1550 OpWrapIndented:= true;
1551 OpWrapEnabledMaxLines:= 60*1000;
1552
1553 OpUndoLimit:= cInitUndoLimit;
1554 OpUndoGrouped:= true;
1555 OpUndoAfterSave:= true;
1556 OpUndoMaxCarets:= cInitUndoMaxCarets;
1557 OpUndoIndentVert:= -5;
1558 OpUndoIndentHorz:= 10;
1559 OpUndoPause:= 300;
1560 OpUndoMouseClicks:= false;
1561
1562 OpCaretBlinkTime:= cInitCaretBlinkTime;
1563 OpCaretBlinkEn:= true;
1564 OpCaretViewNormal:= '2,-100';
1565 OpCaretViewOverwrite:= '-100,-100';
1566 OpCaretViewReadonly:= '-100,2';
1567 OpCaretVirtual:= false;
1568 OpCaretMulti:= true;
1569 OpCaretAfterPasteColumn:= Ord(cPasteCaretColumnRight);
1570 OpCaretsAddedToColumnSel:= true;
1571 OpCaretKeepVisibleOnScroll:= true;
1572 OpCaretsPrimitiveColumnSel:= true;
1573 OpCaretProximityVert:= 0;
1574
1575 OpKeepSelFontColor:= false;
1576 OpShowCurLine:= false;
1577 OpShowCurLineMinimal:= true;
1578 OpShowCurLineOnlyFocused:= false;
1579 OpShowCurCol:= false;
1580 OpShowLastLineOnTop:= true;
1581 OpShowFullBackgroundSel:= false;
1582 OpShowFullBackgroundSyntax:= true;
1583 OpShowMouseSelFrame:= true;
1584 OpCopyLineIfNoSel:= true;
1585 OpCutLineIfNoSel:= false;
1586 OpCopyColumnAlignedBySpaces:= true;
1587 OpSavingTrimSpaces:= false;
1588 OpSavingTrimFinalEmptyLines:= false;
1589 OpSavingForceFinalEol:= false;
1590 OpShowHintOnVertScroll:= false;
1591 OpSmoothScroll:= true;
1592 OpCenteringWidth:= 0;
1593 OpCenteringForDistractionFree:= 0;
1594 OpScrollStyleHorz:= 2; //hide, show, auto
1595 OpLexerDynamicHiliteEnabled:= false;
1596 OpLexerDynamicHiliteMaxLines:= 2000;
1597 OpLexerLineSeparators:= false;
1598 OpZebra:= 0;
1599 OpZebraStep:= 2;
1600 OpDimUnfocused:= 0;
1601 OpCommandLogMaxCount:= 200;
1602
1603 OpNonWordChars:= cDefaultNonWordChars;
1604 OpFoldStyle:= 1;
1605 OpFoldTooltipShow:= false;
1606
1607 OpIndentAuto:= true;
1608 OpIndentAutoKind:= Ord(cIndentAsPrevLine);
1609 OpIndentSize:= 0;
1610 OpIndentAutoRule:= '';
1611 OpUnIndentKeepsAlign:= false;
1612 OpIndentMakesWholeLineSel:= false;
1613
1614 OpMouse2ClickDragSelectsWords:= true;
1615 OpMouseDragDrop:= true;
1616 OpMouseMiddleClickAction:= Ord(TATEditorMiddleClickAction.mcaScrolling);
1617 OpMouseRightClickMovesCaret:= false;
1618 OpMouseEnableColumnSelection:= true;
1619 OpMouseHideCursorOnType:= false;
1620 OpMouseGutterClickSelectedLine:= true;
1621 OpMouseWheelZoom:= true;
1622 OpMouseWheelSpeedVert:= 3;
1623 OpMouseWheelSpeedHorz:= 10;
1624 OpMouseClickNumberSelectsEol:= true;
1625 OpMouseClickLinks:= 2;
1626
1627 OpKeyBackspaceUnindent:= true;
1628 OpKeyBackspaceWrap:= true;
1629 OpKeyTabIndents:= true;
1630 OpKeyHomeToNonSpace:= true;
1631 OpKeyHomeEndNavigateWrapped:= true;
1632 OpKeyEndToNonSpace:= true;
1633 OpKeyPageKeepsRelativePos:= true;
1634 OpKeyPageUpDownSize:= Ord(cPageSizeFullMinus1);
1635 OpKeyUpDownKeepColumn:= true;
1636 OpKeyUpDownNavigateWrapped:= true;
1637 OpKeyUpDownAllowToEdge:= false;
1638 OpKeyLeftRightGoToNextLineWithCarets:= false;
1639 OpKeyLeftRightSwapSel:= true;
1640 OpKeyLeftRightSwapSelAndSelect:= false;
1641
1642 OpBracketHilite:= false;
1643 OpBracketSymbols:= '()[]{}';
1644 OpBracketDistance:= 150;
1645 end;
1646 end;
1647
1648
1649 function IsDoubleBufferedNeeded: boolean;
1650 begin
1651 {$ifdef linux}
1652 //Qt needs true (else caret dont blink, and tab angled borders paint bad)
1653 Exit(true);
1654 {$endif}
1655
1656 Result:= WidgetSet.GetLCLCapability(lcCanDrawOutsideOnPaint) = LCL_CAPABILITY_YES;
1657 end;
1658
1659 {$ifdef windows}
1660 procedure Win32GetUserFont(var AFontName: string; var AFontSize: Integer);
1661 // https://github.com/Alexey-T/CudaText/issues/3039
1662 var
1663 lf: LOGFONT;
1664 begin
1665 ZeroMemory(@lf, SizeOf(lf));
1666 if SystemParametersInfo(SPI_GETICONTITLELOGFONT, SizeOf(lf), @lf, 0) then
1667 begin
1668 AFontName := PChar(Addr(lf.lfFaceName[0]));
1669 AFontSize := MulDiv(-lf.lfHeight, 72, GetDeviceCaps(GetDC(0), LOGPIXELSY));
1670 end;
1671 end;
1672 {$endif}
1673
1674 procedure InitUiOps(var Op: TUiOps);
1675 var
1676 element: TAppHistoryElement;
1677 begin
1678 with Op do
1679 begin
1680 VarFontName:= 'default';
1681 VarFontSize:= 9;
1682
1683 OutputFontName:= VarFontName;
1684 OutputFontSize:= VarFontSize;
1685
1686 DoubleBuffered:= IsDoubleBufferedNeeded;
1687
1688 LexerThemes:= true;
1689 LexerMenuGrouped:= true;
1690 LexerPostponeUntilShown:= true;
1691 LexerParsingMinTimeForEvent:= 600;
1692
1693 SidebarShow:= true;
1694 SidebarOnRight:= false;
1695 SidebarTheme:= 'common_20x20';
1696 SidepanelOnStart:= 0;
1697 BottomOnStart:= 0;
1698 TreeTheme:= 'default_16x16';
1699 ToolBarTheme:= 'default_24x24';
1700
1701 LangName:= '';
1702 ThemeUi:= '';
1703 ThemeSyntax:= '';
1704 ThemeUi_Loaded:= false;
1705 ThemeSyntax_Loaded:= false;
1706
1707 ThemedMainMenu:= true;
1708 ThemedMainMenuFontName:= 'default';
1709 ThemedMainMenuFontSize:= 9;
1710 {$ifdef windows}
1711 if Win32MajorVersion<6 then //Win XP
1712 ThemedMainMenuFontSize:= 8;
1713 Win32GetUserFont(ThemedMainMenuFontName, ThemedMainMenuFontSize);
1714 {$endif}
1715
1716 AutocompleteHtml:= true;
1717 AutocompleteHtml_AutoClose:= true;
1718 AutocompleteHtml_Lexers:= '.*HTML.*|\bPHP\b';
1719 AutocompleteCss:= true;
1720 AutocompleteCss_Lexers:= 'CSS';
1721 AutocompleteFileURI:= true;
1722 AutocompleteInComments:= false;
1723 AutocompleteInCommentsHTML:= true;
1724 AutocompleteInStrings:= true;
1725
1726 HtmlBackgroundColorPair[false]:= $F0F0F0;
1727 HtmlBackgroundColorPair[true]:= $101010;
1728
1729 PyLibrary:= InitPyLibraryPath;
1730 PictureTypes:= 'bmp,png,jpg,jpeg,gif,ico';
1731
1732 DefaultTabSplitIsHorz:= false;
1733 MaxFileSizeToOpen:= 500;
1734 MaxFileSizeForLexer:= 2;
1735 MaxStatusbarMessages:= 35; //Linux gtk2 shows maximal ~38 lines in tooltip
1736
1737 ListboxCentered:= true;
1738 ListboxSizeX:= 450;
1739 ListboxSizeY:= 300;
1740 ListboxCompleteSizeX:= 550;
1741 ListboxCompleteSizeY:= 200;
1742 ListboxFuzzySearch:= true;
1743 ListboxHotkeyFontSizeDelta:= 0; //2 gives too small hotkey font on Lin/Win
1744
1745 TabsShowFoldersSuffix:= true;
1746 TabsShowFoldersMaxLevels:= 3;
1747 TabsResetUntitledCounter:= true;
1748 TabsDisabled:= false;
1749 TabVarWidth:= false;
1750 TabMultiline:= false;
1751 TabAngled:= false;
1752 TabFlat:= false;
1753 TabWidth:= 170;
1754 TabWidthMin:= 40;
1755 TabWidthMax:= 300;
1756 TabHeight:= 26;
1757 TabHeightInner:= TabHeight-1;
1758 TabSpacer:= 2;
1759 TabSpaceBeforeText:= 6;
1760 TabPosition:= 0;
1761 TabColorFull:= false;
1762 TabFontScale:= 100;
1763 TabShowX:= 1; //show all
1764 TabShowXSize:= 14;
1765 TabShowXRounded:= true;
1766 TabShowPlus:= true;
1767 TabDblClickClose:= false;
1768 TabNumbers:= false;
1769 TabNewNearCurrent:= false;
1770 TabRecentOnClose:= false;
1771 TabButtonLayout:= '<>,v';
1772 TabPreviewFontStyle:= 'iu';
1773 TabSwitcherDialog:= true;
1774
1775 MaxHistoryEdits:= 20;
1776 MaxHistoryMenu:= 10;
1777 MaxHistoryFiles:= 25;
1778
1779 CmdPaletteFilterKeep:= false;
1780 CmdPaletteFilterText:= '';
1781
1782 HistoryDisabledStr:= '';
1783 for element:= Low(element) to High(element) do
1784 HistoryItems[element]:= true;
1785
1786 FindSuggestSel:= true;
1787 FindSuggestWord:= false;
1788 FindSuggestInSelection:= false;
1789 FindCurrentWordCaseSensitive:= ufcsCaseFromDialog;
1790 FindShowNoResultsByInputBgColor:= true;
1791
1792 FindHiddenButtons:= '';
1793 FindShow_FindFirst:= true;
1794 FindShow_FindNext:= true;
1795 FindShow_FindPrev:= true;
1796 FindShow_ReplaceAll:= true;
1797 FindShow_ReplaceGlobal:= true;
1798 FindShow_RegEx:= true;
1799 FindShow_CaseSens:= true;
1800 FindShow_WholeWords:= true;
1801 FindShow_Wrapped:= true;
1802 FindShow_InSel:= true;
1803 FindShow_MultiLine:= true;
1804 FindShow_SyntaxElements:= true;
1805 FindShow_HiAll:= true;
1806 FindShow_ConfirmRep:= true;
1807 FindShow_RegexSubst:= true;
1808
1809 FindIndentVert:= -5;
1810 FindIndentHorz:= 10;
1811 FindMultiLineScale:= 2.5;
1812 FindSeparateForm:= false;
1813 FindHiAll_MaxLines:= 1000;
1814 FindHiAll_TagValue:= 99; //GET_UNIQUE_TAG starts with 120
1815 FindOccur_TagValue:= 98;
1816
1817 AllowProgramUpdates:= true;
1818 EscapeClose:= false;
1819 EscapeCloseConsole:= true;
1820 ConsoleWordWrap:= true;
1821 InputHeight:= 26;
1822 InitialDir:= '';
1823 ConfirmLinksClicks:= true;
1824 ConfirmSaveEmptyUntitledTab:= false;
1825
1826 ExportHtmlNumbers:= false;
1827 ExportHtmlFontSize:= 12;
1828 ExportHtmlFontName:= 'Courier New';
1829
1830 TreeAutoSync:= true;
1831 TreeTimeFill:= 2000;
1832 //TreeTimeCaret:= 300;
1833 TreeShowIcons:= true;
1834 TreeShowTooltips:= {$ifdef LCLQt5} false; {$else} true; {$endif} //solve issue #3642
1835 TreeFilterLayout:= 1;
1836 TreeSublexers:= false;
1837 TreeIconFilenames:= 'dir,st1,st2,st3,box,fx,ar1,ar2,';
1838
1839 PyChangeSlow:= 2000;
1840 InfoAboutOptionsEditor:= true;
1841 AllowFrameParsing:= false;
1842 AllowRunPkExec:= true;
1843
1844 LogPluginIniting:= true;
1845 LogSessions:= true;
1846 LogDebug:= false;
1847 LogConsole:= false;
1848 LogConsoleDetailedStartupTime:= false; //true;
1849
1850 NewdocLexer:= '';
1851 NewdocEnc:= 'utf8';
1852 NewdocEnds:= 0;
1853
1854 DefaultEncUtf8:= {$ifdef windows} false {$else} true {$endif};
1855 ViewerBinaryWidth:= 100;
1856 ViewerNonPrintable:= false;
1857
1858 StatusNoSel:= '{_ln} {y}, {_col} {xx}';
1859 StatusSmallSel:= '{_ln} {y}, {_col} {xx}, {_sel}';
1860 StatusStreamSel:= '{_ln} {y}, {_col} {xx}, {sel} {_linesel}';
1861 StatusColSel:= '{sel}x{cols} {_sel}';
1862 StatusCarets:= '{carets} {_carets}, {sel} {_linesel}';
1863
1864 StatusPanels:= 'caret,C,180|enc,C,125|ends,A,45|lexer,C,140|tabsize,A,75|selmode,A,15|msg,L,4000';
1865 StatusTime:= 5;
1866 StatusHeightPercents:= 180;
1867 StatusHeightMin:= 20;
1868
1869 AltTooltipTime:= 9;
1870 AltTooltipTimeMax:= 60;
1871 AltTooltipPaddingX:= 6;
1872 AltTooltipPaddingY:= 3;
1873
1874 ScrollbarWidth:= 14;
1875 ScrollbarBorderSize:= 0;
1876 ScrollbarArrowSize:= 3;
1877
1878 ProgressbarWidth:= 50;
1879 ProgressbarHeightSmall:= 6;
1880
1881 ShowMenubar:= true;
1882 ShowStatusbar:= true;
1883 ShowToolbar:= false;
1884 ShowTitlePath:= false;
1885
1886 Scale:= 100;
1887 ScaleFont:= 100;
1888
1889 ReopenSession:= true;
1890 ReopenSessionWithCmdLine:= false;
1891 SessionSaveInterval:= 30;
1892 SessionSaveOnExit:= false;
1893 BackupLastSessions:= 0;
1894 SaveModifiedTabsOnClose:= true;
1895
1896 ShowFormsOnTop:= false;
1897 ShowMenuDialogsWithBorder:= {$ifdef LCLGTK2} true {$else} false {$endif};
1898 UndoPersistent:= '';
1899 AllowSaveOfUnmodifiedFile:= true;
1900
1901 PluginDialogsShowInTaskbar:= {$ifdef windows} false {$else} true {$endif}; //to fix issue #3078 on Linux
1902 PluginDialogsModalFormStyle:= {$ifdef LCLQT5} fsNormal {$else} fsStayOnTop {$endif};
1903 FloatGroupsShowInTaskbar:= stAlways;
1904 OneInstance:= true;
1905 NotificationEnabled:= true;
1906 NotificationTimeSeconds:= 2;
1907 NotificationConfirmReload:= 1;
1908 MarkFilesDeletedOutsideAsModified:= true;
1909 NonTextFiles:= 0;
1910 NonTextFilesBufferKb:= 64;
1911 ReloadFollowTail:= true;
1912 ReloadUnsavedConfirm:= true;
1913 CheckLowDiskSpace:= 1*1024*1024;
1914 FullScreen:= 'tp';
1915 MouseGotoDefinition:= 'a';
1916
1917 Emmet_AddSlashToEmptyTags:= true;
1918 Emmet_CommentTags:= false;
1919 Emmet_IndentNested:= true;
1920 Emmet_SingleLine:= false;
1921 Emmet_TrimLineMarkers:= true;
1922 Emmet_WordWrap:= false;
1923
1924 HotkeyFindDialog:= 'Ctrl+F';
1925 HotkeyReplaceDialog:= 'Ctrl+R';
1926 HotkeyFindFirst:= 'Alt+Enter';
1927 HotkeyFindNext:= '';
1928 HotkeyFindPrev:= 'Shift+Enter';
1929 HotkeyReplaceAndFindNext:= 'Alt+Z';
1930 HotkeyReplaceNoFindNext:= 'Ctrl+Alt+Z';
1931 HotkeyReplaceAll:= 'Alt+A';
1932 HotkeyReplaceGlobal:= '';
1933 HotkeyCountAll:= 'Alt+O';
1934 HotkeyExtractAll:= 'Alt+Q';
1935 HotkeySelectAll:= 'Alt+E';
1936 HotkeyMarkAll:= 'Alt+K';
1937 HotkeyToggleRegex:= 'Alt+R';
1938 HotkeyToggleCaseSens:= 'Alt+C';
1939 HotkeyToggleWords:= 'Alt+W';
1940 HotkeyToggleWrapped:= 'Alt+N';
1941 HotkeyToggleInSelect:= 'Alt+X';
1942 HotkeyToggleMultiline:= 'Alt+M';
1943 HotkeyToggleConfirmRep:= 'Alt+Y';
1944 HotkeyToggleTokens:= '';
1945 HotkeyToggleHiAll:= '';
1946 end;
1947 end;
1948
1949
1950 procedure SReplaceSpecialFilenameChars(var S: string);
1951 begin
1952 S:= StringReplace(S, '/', '_', [rfReplaceAll]);
1953 S:= StringReplace(S, '\', '_', [rfReplaceAll]);
1954 S:= StringReplace(S, '*', '_', [rfReplaceAll]);
1955 S:= StringReplace(S, ':', '_', [rfReplaceAll]);
1956 S:= StringReplace(S, '<', '_', [rfReplaceAll]);
1957 S:= StringReplace(S, '>', '_', [rfReplaceAll]);
1958 end;
1959
1960 function GetAppLexerSpecificConfig(ALexer: string; ADefaultConfig: boolean=false): string;
1961 var
1962 dir: string;
1963 begin
1964 //support none-lexer here
1965 if ALexer='' then
1966 ALexer:= '-';
1967 SReplaceSpecialFilenameChars(ALexer);
1968
1969 if ADefaultConfig then
1970 dir:= AppDir_SettingsDefault
1971 else
1972 dir:= AppDir_Settings;
1973
1974 Result:= dir+DirectorySeparator+'lexer '+ALexer+'.json';
1975 end;
1976
1977 function GetAppFilenameIsIgnoredForSession(const AFilename: string): boolean;
1978 var
1979 SName: string;
1980 begin
1981 SName:= ExtractFileName(AFilename);
1982 Result:= SameFileName(ExtractFileDir(AFilename), AppDir_Settings) and
1983 ( SameFileName(SName, 'history.json') or
1984 SameFileName(SName, 'history session.json') );
1985 end;
1986
1987 function AppFile_HotkeysForLexer(AName: string): string;
1988 begin
1989 //support none-lexer
1990 if AName='' then
1991 AName:= '-';
1992 SReplaceSpecialFilenameChars(AName);
1993 Result:= AppDir_Settings+DirectorySeparator+'keys lexer '+AName+'.json';
1994 end;
1995
1996
1997 class function TPluginHelper.HotkeyStringId_To_CommandCode(const AId: string): integer;
1998 begin
1999 //plugin item 'module,method'
2000 if Pos(',', AId)>0 then
2001 begin
2002 Result:= CommandGetIndexFromModuleAndMethod(AId);
2003 if Result>=0 then
2004 Inc(Result, cmdFirstPluginCommand);
2005 end
2006 else
2007 //usual item
2008 Result:= StrToIntDef(AId, -1);
2009 end;
2010
2011 class function TPluginHelper.Debug_PluginCommands(const AModule: string): string;
2012 var
2013 CmdItem: TAppCommandInfo;
2014 i: integer;
2015 begin
2016 Result:= '';
2017 for i:= 0 to AppCommandList.Count-1 do
2018 begin
2019 CmdItem:= TAppCommandInfo(AppCommandList[i]);
2020 if CmdItem.ItemModule=AModule then
2021 Result+= CmdItem.CommaStr+#10;
2022 end;
2023 end;
2024
2025
2026 function DoReadOneStringFromFile(const AFilename: string): string;
2027 var
2028 f: TextFile;
2029 begin
2030 Result:= '';
2031 Assign(f, AFilename);
2032 Reset(f);
2033 if IOResult=0 then
2034 begin
2035 if not Eof(f) then
2036 Readln(f, Result);
2037 CloseFile(f);
2038 end;
2039 end;
2040
2041 function DoReadContentFromFile(const AFilename: string): string;
2042 var
2043 L: TStringList;
2044 begin
2045 Result:= '';
2046 if not FileExists(AFilename) then exit;
2047
2048 L:= TStringList.Create;
2049 try
2050 L.LoadFromFile(AFilename);
2051 L.TextLineBreakStyle:= tlbsLF;
2052 if L.Count>0 then
2053 Result:= L.Text;
2054 finally
2055 FreeAndNil(L);
2056 end;
2057 end;
2058
2059 procedure DoWriteStringToFile(const AFilename, AText: string);
2060 var
2061 f: TextFile;
2062 begin
2063 Assign(f, AFilename);
2064 Rewrite(f);
2065 if IOResult=0 then
2066 begin
2067 Write(f, AText);
2068 CloseFile(f);
2069 end;
2070 end;
2071
2072
2073 function DoLexerDetectByFilenameOrContent(const AFilename: string;
2074 AChooseFunc: TecLexerChooseFunc): TecSyntAnalyzer;
2075 const
2076 cSignUTF8: string = #$EF#$BB#$BF;
2077 var
2078 SNameOnly: string;
2079 Item: TAppKeyValue;
2080 ext, sLine, res: string;
2081 i: integer;
2082 begin
2083 SNameOnly:= ExtractFileName(AFilename);
2084
2085 //detect by filename
2086 res:= AppConfig_Detect.GetValue(SNameOnly, '');
2087 if res<>'' then
2088 exit(AppManager.FindLexerByName(res));
2089
2090 //detect by double extention
2091 if SFindCharCount(SNameOnly, '.')>1 then
2092 begin
2093 i:= RPos('.', SNameOnly);
2094 i:= RPosEx('.', SNameOnly, i-1);
2095 ext:= Copy(SNameOnly, i, MaxInt);
2096 if ext<>'' then
2097 begin
2098 res:= AppConfig_Detect.GetValue('*'+ext, '');
2099 if res<>'' then
2100 exit(AppManager.FindLexerByName(res));
2101 end;
2102 end;
2103
2104 //detect by usual extention
2105 ext:= ExtractFileExt(SNameOnly);
2106 if ext<>'' then
2107 begin
2108 res:= AppConfig_Detect.GetValue('*'+ext, '');
2109 if res<>'' then
2110 exit(AppManager.FindLexerByName(res));
2111 end;
2112
2113 //detect by first line
2114 if AppConfig_DetectLine.Count>0 then
2115 begin
2116 sLine:= DoReadOneStringFromFile(AFilename);
2117 if sLine<>'' then
2118 begin
2119 //skip UTF8 signature, needed for XMLs
2120 if SBeginsWith(sLine, cSignUTF8) then
2121 Delete(sLine, 1, Length(cSignUTF8));
2122 for i:= 0 to AppConfig_DetectLine.Count-1 do
2123 begin
2124 Item:= TAppKeyValue(AppConfig_DetectLine[i]);
2125 if SRegexMatchesString(sLine, Item.Key, true) then
2126 exit(AppManager.FindLexerByName(Item.Value));
2127 end;
2128 end;
2129 end;
2130
2131 Result:= AppManager.FindLexerByFilename(AFilename, AChooseFunc);
2132 end;
2133
2134 class function TPluginHelper.CommandCode_To_HotkeyStringId(ACmd: integer): string;
2135 begin
2136 if CommandCategory(ACmd) in [categ_Plugin, categ_PluginSub] then
2137 Result:= TAppCommandInfo(AppCommandList[ACmd-cmdFirstPluginCommand]).CommaStr
2138 else
2139 Result:= IntToStr(ACmd);
2140 end;
2141
2142 class procedure TKeymapHelper.ItemSaveToConfig(K: TATKeymapItem; const path, ALexerName: string;
2143 ALexerSpecific: boolean);
2144 var
2145 SFilename: string;
2146 c: TJSONConfig;
2147 sl: TStringList;
2148 i: integer;
2149 begin
2150 if ALexerSpecific then
2151 SFilename:= AppFile_HotkeysForLexer(ALexerName)
2152 else
2153 SFilename:= AppFile_Hotkeys;
2154
2155 c:= TJSONConfig.Create(nil);
2156 sl:= TStringlist.create;
2157 try
2158 try
2159 c.Formatted:= true;
2160 c.Filename:= SFilename;
2161 except
2162 exit;
2163 end;
2164
2165 c.SetValue(path+'/name', K.Name);
2166
2167 sl.Clear;
2168 for i:= 0 to High(TATKeyArray.Data) do
2169 if K.Keys1.Data[i]<>0 then
2170 sl.Add(ShortCutToText(K.Keys1.Data[i]));
2171 c.SetValue(path+'/s1', sl);
2172
2173 sl.clear;
2174 for i:= 0 to High(TATKeyArray.Data) do
2175 if K.Keys2.Data[i]<>0 then
2176 sl.Add(ShortCutToText(K.Keys2.Data[i]));
2177
2178 if sl.Count>0 then
2179 c.SetValue(path+'/s2', sl)
2180 else
2181 c.DeleteValue(path+'/s2')
2182 finally
2183 c.Free;
2184 sl.Free;
2185 end;
2186 end;
2187
2188
2189 class procedure TKeymapHelper.ItemDeleteInConfig(K: TATKeymapItem; const path, ALexerName: string;
2190 ALexerSpecific: boolean);
2191 var
2192 SFilename: string;
2193 c: TJSONConfig;
2194 begin
2195 if ALexerSpecific then
2196 SFilename:= AppFile_HotkeysForLexer(ALexerName)
2197 else
2198 SFilename:= AppFile_Hotkeys;
2199
2200 c:= TJSONConfig.Create(nil);
2201 try
2202 try
2203 c.Formatted:= true;
2204 c.Filename:= SFilename;
2205 except
2206 exit;
2207 end;
2208
2209 if c.GetValue(path+'/name', '')<>'' then
2210 c.DeletePath(path);
2211 finally
2212 c.Free;
2213 end;
2214 end;
2215
2216
2217 class function TKeymapHelper.SaveKey_ForPlugin(AKeymap: TATKeymap;
2218 AOverwriteKey: boolean;
2219 const AMenuitemCaption, AModuleName, AMethodName, ALexerName, AHotkey: string): boolean;
2220 const
2221 cKeyComboSeparator = '|';
2222 var
2223 SFilename: string;
2224 c: TJSONConfig;
2225 sl: TStringList;
2226 path, s_item: string;
2227 Sep: TATStringSeparator;
2228 begin
2229 Result:= false;
2230
2231 if ALexerName<>'' then
2232 SFilename:= AppFile_HotkeysForLexer(ALexerName)
2233 else
2234 SFilename:= AppFile_Hotkeys;
2235
2236 c:= TJSONConfig.Create(nil);
2237 sl:= TStringlist.create;
2238 try
2239 try
2240 c.Formatted:= true;
2241 c.Filename:= SFilename;
2242 except
2243 exit;
2244 end;
2245
2246 path:= AModuleName+','+AMethodName;
2247
2248 //check: this command has already any hotkey?
2249 if not AOverwriteKey then
2250 if c.GetValue(path+'/s1', sl, '') then exit;
2251
2252 c.SetValue(path+'/name', AMenuitemCaption);
2253
2254 sl.Clear;
2255 Sep.Init(AHotkey, cKeyComboSeparator);
2256 while Sep.GetItemStr(s_item) do
2257 sl.Add(s_item);
2258
2259 c.SetValue(path+'/s1', sl);
2260 Result:= true;
2261 finally
2262 c.Free;
2263 sl.Free;
2264 end;
2265 end;
2266
2267 function AppListboxItemHeight(AScale, ADoubleHeight: boolean): integer;
2268 begin
2269 Result:= UiOps.VarFontSize * 18 div 10 +2;
2270
2271 {$ifdef windows}
2272 Result:= Result * Screen.PixelsPerInch div 96;
2273 {$endif}
2274
2275 if ADoubleHeight then
2276 Result:= Result * 185 div 100;
2277 if AScale then
2278 Result:= AppScaleFont(Result);
2279 end;
2280
2281
2282 procedure DoLexerEnum(L: TStringList; AlsoDisabled: boolean = false);
2283 var
2284 an: TecSyntAnalyzer;
2285 i: integer;
2286 begin
2287 with AppManager do
2288 for i:= 0 to LexerCount-1 do
2289 begin
2290 an:= Lexers[i];
2291 if an.Deleted then Continue;
2292 if an.Internal and not AlsoDisabled then Continue;
2293 L.Add(an.LexerName);
2294 end;
2295
2296 with AppManagerLite do
2297 for i:= 0 to LexerCount-1 do
2298 L.Add(Lexers[i].LexerName+msgLiteLexerSuffix);
2299 end;
2300
2301 {
2302 procedure DoLexerSave(an: TecSyntAnalyzer);
2303 begin
2304 if Assigned(an) then
2305 an.SaveToFile(GetAppLexerFilename(an.LexerName));
2306 end;
2307 }
2308
2309 class function TPluginHelper.CommandGetIndexFromModuleAndMethod(const AText: string): integer;
2310 var
2311 Sep: TATStringSeparator;
2312 SModule, SProc, SProcParam: string;
2313 AppCmd: TAppCommandInfo;
2314 i: integer;
2315 begin
2316 Result:= -1;
2317
2318 Sep.Init(AText);
2319 Sep.GetItemStr(SModule);
2320 Sep.GetItemStr(SProc);
2321 Sep.GetItemStr(SProcParam);
2322
2323 if SModule='' then exit;
2324 if SProc='' then exit;
2325
2326 for i:= 0 to AppCommandList.Count-1 do
2327 begin
2328 AppCmd:= TAppCommandInfo(AppCommandList[i]);
2329 if (AppCmd.ItemModule=SModule) and
2330 (AppCmd.ItemProc=SProc) and
2331 (AppCmd.ItemProcParam=SProcParam) then
2332 exit(i);
2333 end;
2334 end;
2335
2336
2337 class procedure TPluginHelper.CommandUpdateSubcommands(const AText: string);
2338 const
2339 cSepRoot=';';
2340 cSepParams=#10;
2341 cSepNameParam=#9;
2342 var
2343 Sep: TATStringSeparator;
2344 SModule, SProc, SParams, SItem, SItemParam, SItemCaption: string;
2345 CmdItem: TAppCommandInfo;
2346 N: integer;
2347 begin
2348 Sep.Init(AText, cSepRoot);
2349 Sep.GetItemStr(SModule);
2350 Sep.GetItemStr(SProc);
2351 Sep.GetRest(SParams);
2352
2353 //del items for module/method
2354 for N:= AppCommandList.Count-1 downto 0 do
2355 with TAppCommandInfo(AppCommandList[N]) do
2356 if (ItemModule=SModule) and (ItemProc=SProc) and (ItemProcParam<>'') then
2357 AppCommandList.Delete(N);
2358
2359 //add items for SParams
2360 Sep.Init(SParams, cSepParams);
2361 repeat
2362 if not Sep.GetItemStr(SItem) then Break;
2363 SSplitByChar(SItem, cSepNameParam, SItemCaption, SItemParam);
2364
2365 CmdItem:= TAppCommandInfo.Create;
2366 CmdItem.ItemModule:= SModule;
2367 CmdItem.ItemProc:= SProc;
2368 CmdItem.ItemProcParam:= SItemParam;
2369 CmdItem.ItemCaption:= SItemCaption;
2370 CmdItem.ItemFromApi:= true;
2371
2372 AppCommandList.Add(CmdItem);
2373 until false;
2374 end;
2375
2376
2377 function GetAppLangFilename: string;
2378 begin
2379 if UiOps.LangName='' then
2380 Result:= ''
2381 else
2382 Result:= AppDir_DataLang+DirectorySeparator+UiOps.LangName+'.ini';
2383 end;
2384
2385 function EscapeLexerFilename(const ALexName: string): string;
2386 begin
2387 Result:= ALexName;
2388 if Result<>'' then
2389 begin
2390 Result:= StringReplace(Result, ':', '_', [rfReplaceAll]);
2391 Result:= StringReplace(Result, '/', '_', [rfReplaceAll]);
2392 Result:= StringReplace(Result, '\', '_', [rfReplaceAll]);
2393 Result:= StringReplace(Result, '*', '_', [rfReplaceAll]);
2394 end;
2395 end;
2396
2397 function GetLexerFilenameWithExt(ALexName, AExt: string): string;
2398 begin
2399 if ALexName<>'' then
2400 Result:= AppDir_Lexers+DirectorySeparator+EscapeLexerFilename(ALexName)+AExt
2401 else
2402 Result:= '';
2403 end;
2404
2405 function GetAppLexerMapFilename(const ALexName: string): string;
2406 begin
2407 Result:= GetLexerFilenameWithExt(ALexName, '.cuda-lexmap');
2408 end;
2409
2410 function GetAppLexerFilename(const ALexName: string): string;
2411 begin
2412 Result:= GetLexerFilenameWithExt(ALexName, '.lcf');
2413 end;
2414
2415 function GetAppLexerOpsFilename(const ALexName: string): string;
2416 begin
2417 Result:= AppDir_Settings+DirectorySeparator+EscapeLexerFilename(ALexName)+'.cuda-lexops';
2418 end;
2419
2420 function GetAppLexerAcpFilename(const ALexName: string): string;
2421 begin
2422 Result:= AppDir_DataAutocomplete+DirectorySeparator+EscapeLexerFilename(ALexName)+'.acp';
2423 end;
2424
2425 function GetAppUndoFilename(const fn: string; IsRedo: boolean): string;
2426 const
2427 Ext: array[boolean] of string = ('.undx', '.redx');
2428 begin
2429 Result:= ExtractFileDir(fn)+DirectorySeparator+
2430 '.cudatext'+DirectorySeparator+
2431 ExtractFileName(fn)+Ext[IsRedo];
2432 end;
2433
2434 class function TKeymapHelper.GetHotkey(AKeymap: TATKeymap; const ACmdString: string): string;
2435 var
2436 NCode, NIndex: integer;
2437 begin
2438 Result:= '';
2439 if Pos(',', ACmdString)=0 then
2440 NCode:= StrToIntDef(ACmdString, 0)
2441 else
2442 begin
2443 NIndex:= TPluginHelper.CommandGetIndexFromModuleAndMethod(ACmdString);
2444 if NIndex<0 then exit;
2445 NCode:= NIndex+cmdFirstPluginCommand;
2446 end;
2447
2448 NIndex:= AKeymap.IndexOf(NCode);
2449 if NIndex<0 then exit;
2450 with AKeymap[NIndex] do
2451 Result:= Keys1.ToString+'|'+Keys2.ToString;
2452 end;
2453
2454
2455 class function TKeymapHelper.SetHotkey(AKeymap: TATKeymap; const AParams: string; AndSaveFile: boolean): boolean;
2456 var
2457 Sep: TATStringSeparator;
2458 NCode, NIndex: integer;
2459 SCmd, SKey1, SKey2: string;
2460 begin
2461 Result:= false;
2462
2463 Sep.Init(AParams, '|');
2464 Sep.GetItemStr(SCmd);
2465 Sep.GetItemStr(SKey1);
2466 Sep.GetItemStr(SKey2);
2467
2468 if Pos(',', SCmd)=0 then
2469 NCode:= StrToIntDef(SCmd, 0)
2470 else
2471 begin
2472 NIndex:= TPluginHelper.CommandGetIndexFromModuleAndMethod(SCmd);
2473 if NIndex<0 then exit;
2474 NCode:= NIndex+cmdFirstPluginCommand;
2475 end;
2476
2477 NIndex:= AKeymap.IndexOf(NCode);
2478 if NIndex<0 then exit;
2479 with AKeymap[NIndex] do
2480 begin
2481 Keys1.SetFromString(SKey1);
2482 Keys2.SetFromString(SKey2);
2483
2484 //save to keys.json
2485 //Py API: no need lexer-specific
2486 if AndSaveFile then
2487 ItemSaveToConfig(AKeymap[NIndex], SCmd, '', false);
2488 end;
2489 Result:= true;
2490 end;
2491
2492
2493 class procedure TKeymapHelper.ClearKey(AKeymap: TATKeymap; AItemIndex, AKeyIndex: integer);
2494 begin
2495 with AKeymap do
2496 if IsIndexValid(AItemIndex) then
2497 with Items[AItemIndex] do
2498 if AKeyIndex=0 then
2499 Keys1.Clear
2500 else
2501 Keys2.Clear;
2502 end;
2503
2504 class procedure TKeymapHelper.ClearKeyInAll(AItemIndex, AKeyIndex: integer);
2505 var
2506 iMap: integer;
2507 begin
2508 ClearKey(AppKeymapMain, AItemIndex, AKeyIndex);
2509
2510 for iMap:= 0 to AppKeymapLexers.Count-1 do
2511 ClearKey(
2512 TATKeymap(AppKeymapLexers.Objects[iMap]),
2513 AItemIndex, AKeyIndex);
2514 end;
2515
2516 class function TKeymapHelper.CheckDuplicateForCommand(
2517 AKeymapItem: TATKeymapItem;
2518 const ALexerName: string;
2519 AOverwriteAndSave: boolean): integer;
2520 var
2521 Map: TATKeymap;
2522 MapItem: TATKeymapItem;
2523 ShortKeys1: TATKeyArray;
2524 ShortKeys2: TATKeyArray;
2525 StrId: string;
2526 NKeyIndex: integer;
2527 iCmd: integer;
2528 begin
2529 Result:= 0;
2530
2531 Map:= AppKeymapMain;
2532 NKeyIndex:= 0;
2533
2534 ShortKeys1.Clear;
2535 ShortKeys2.Clear;
2536 if AKeymapItem.Keys1.Length>1 then
2537 ShortKeys1:= AKeymapItem.ShortenedKeys1;
2538 if AKeymapItem.Keys2.Length>1 then
2539 ShortKeys2:= AKeymapItem.ShortenedKeys2;
2540
2541 for iCmd:= 0 to Map.Count-1 do
2542 begin
2543 MapItem:= Map.Items[iCmd];
2544 if MapItem.Command=AKeymapItem.Command then Continue;
2545
2546 if (AKeymapItem.Keys1.IsConflictWith(MapItem.Keys1)) or
2547 (AKeymapItem.Keys2.IsConflictWith(MapItem.Keys1)) then
2548 NKeyIndex:= 0
2549 else
2550 if (AKeymapItem.Keys1.IsConflictWith(MapItem.Keys2)) or
2551 (AKeymapItem.Keys2.IsConflictWith(MapItem.Keys2)) then
2552 NKeyIndex:= 1
2553 else
2554 Continue;
2555
2556 if AOverwriteAndSave then
2557 begin
2558 //clear item in ALL existing keymaps
2559 ClearKeyInAll(iCmd, NKeyIndex);
2560
2561 StrId:= TPluginHelper.CommandCode_To_HotkeyStringId(MapItem.Command);
2562
2563 //save to "keys.json"
2564 ItemSaveToConfig(MapItem, StrId, '', false);
2565
2566 //save to "keys nn.json"
2567 if ALexerName<>'' then
2568 ItemSaveToConfig(MapItem, StrId, ALexerName, true);
2569 end
2570 else
2571 Result:= MapItem.Command;
2572
2573 Break;
2574 end;
2575 end;
2576
2577 class procedure TKeymapHelper.LoadConfig(AKeymap: TATKeymap; const AFileName: string; AForLexer: boolean);
2578 var
2579 cfg: TJSONConfig;
2580 slist, skeys: TStringList;
2581 //
2582 procedure DoReadConfigToKeys(const path: string; var keys: TATKeyArray);
2583 var
2584 j: integer;
2585 begin
2586 FillChar(keys, SizeOf(keys), 0);
2587 cfg.GetValue(path, skeys, '');
2588 for j:= 0 to skeys.count-1 do
2589 if skeys[j]<>'' then
2590 keys.Data[j]:= TextToShortCut(skeys[j]);
2591 end;
2592 //
2593 var
2594 StrId: string;
2595 ncmd, nitem, i: integer;
2596 begin
2597 cfg:= TJSONConfig.Create(nil);
2598 slist:= TStringList.Create;
2599 skeys:= TStringList.Create;
2600
2601 try
2602 try
2603 cfg.Formatted:= true;
2604 cfg.Filename:= AFileName;
2605 except
2606 exit;
2607 end;
2608
2609 cfg.EnumSubKeys('/', slist);
2610 for i:= 0 to slist.count-1 do
2611 begin
2612 StrId:= slist[i];
2613 ncmd:= TPluginHelper.HotkeyStringId_To_CommandCode(StrId);
2614 if ncmd<0 then Continue;
2615
2616 nitem:= AKeymap.IndexOf(ncmd);
2617 if nitem<0 then Continue;
2618
2619 DoReadConfigToKeys(StrId+'/s1', AKeymap[nitem].Keys1);
2620 DoReadConfigToKeys(StrId+'/s2', AKeymap[nitem].Keys2);
2621 AKeymap[nitem].LexerSpecific:= AForLexer;
2622 end;
2623 finally
2624 skeys.Free;
2625 slist.Free;
2626 cfg.Free;
2627 end;
2628 end;
2629
2630
2631 class function TKeymapHelper.GetForLexer(const ALexer: string): TATKeymap;
2632 var
2633 Keymap: TATKeymap;
2634 N: integer;
2635 begin
2636 N:= AppKeymapLexers.IndexOf(ALexer);
2637 if N>=0 then
2638 begin
2639 Result:= TATKeymap(AppKeymapLexers.Objects[N]);
2640 exit;
2641 end;
2642
2643 Keymap:= TATKeymap.Create;
2644 Keymap.Assign(AppKeymapMain);
2645 AppKeymapLexers.AddObject(ALexer, Keymap);
2646
2647 LoadConfig(Keymap,
2648 AppFile_HotkeysForLexer(ALexer), true);
2649
2650 Result:= Keymap;
2651 end;
2652
2653
2654 procedure MsgStdout(const Str: string; AllowMsgBox: boolean = false);
2655 begin
2656 {$ifdef windows}
2657 if AllowMsgBox then
2658 MsgBox(Str, MB_OK+MB_ICONINFORMATION);
2659 {$else}
2660 System.Writeln(Str);
2661 {$endif}
2662 end;
2663
2664 procedure MsgLogConsole(const AText: string);
2665 var
2666 Sep: TATStringSeparator;
2667 S: UnicodeString;
2668 begin
2669 if Pos(#10, AText)=0 then
2670 AppConsoleQueue.Push(AText)
2671 else
2672 begin
2673 Sep.Init(AText, #10);
2674 while Sep.GetItemStr(S) do
2675 AppConsoleQueue.Push(S);
2676 end;
2677 end;
2678
2679
2680 function AppEncodingShortnameToFullname(const S: string): string;
2681 var
2682 i: integer;
2683 begin
2684 Result:= '';
2685 if S='' then exit;
2686 for i:= Low(AppEncodings) to High(AppEncodings) do
2687 with AppEncodings[i] do
2688 if SameText(S, ShortName) then
2689 Exit(Name);
2690 end;
2691
2692 function AppEncodingFullnameToShortname(const S: string): string;
2693 var
2694 i: integer;
2695 begin
2696 Result:= '';
2697 if S='' then exit;
2698 for i:= Low(AppEncodings) to High(AppEncodings) do
2699 with AppEncodings[i] do
2700 if SameText(S, Name) then
2701 Exit(LowerCase(ShortName));
2702 end;
2703
2704 function AppEncodingListAsString: string;
2705 var
2706 i: integer;
2707 begin
2708 Result:= '';
2709 for i:= Low(AppEncodings) to High(AppEncodings) do
2710 with AppEncodings[i] do
2711 if ShortName<>'' then
2712 Result:= Result + LowerCase(ShortName) + #10;
2713 end;
2714
2715 procedure UpdateFormOnTop(F: TForm);
2716 begin
2717 if UiOps.ShowFormsOnTop then
2718 F.FormStyle:= fsSystemStayOnTop
2719 else
2720 F.FormStyle:= fsNormal;
2721 end;
2722
2723 procedure DoStatusbarTextByTag(AStatus: TATStatus; ATag: PtrInt; const AText: string);
2724 var
2725 NIndex: integer;
2726 begin
2727 NIndex:= AStatus.FindPanel(ATag);
2728 if NIndex>=0 then
2729 AStatus.Captions[NIndex]:= AText;
2730 end;
2731
2732 procedure DoStatusbarHintByTag(AStatus: TATStatus; ATag: PtrInt; const AText: string);
2733 var
2734 NIndex: integer;
2735 begin
2736 NIndex:= AStatus.FindPanel(ATag);
2737 if NIndex>=0 then
2738 AStatus.Hints[NIndex]:= AText;
2739 end;
2740
2741 procedure DoStatusbarColorByTag(AStatus: TATStatus; ATag: PtrInt; AColor: TColor);
2742 var
2743 NIndex: integer;
2744 Data: TATStatusData;
2745 begin
2746 NIndex:= AStatus.FindPanel(ATag);
2747 if NIndex>=0 then
2748 begin
2749 Data:= AStatus.GetPanelData(NIndex);
2750 Data.ColorFont:= AColor;
2751 AStatus.Invalidate;
2752 end;
2753 end;
2754
2755 function IsFileTooBigForOpening(const AFilename: string): boolean;
2756 begin
2757 Result:= (AFilename<>'') and (FileSize(AFileName) div (1024*1024) >= UiOps.MaxFileSizeToOpen);
2758 end;
2759
2760 function IsFileTooBigForLexer(const AFilename: string): boolean;
2761 begin
2762 Result:= (AFilename<>'') and (FileSize(AFilename) div (1024*1024) >= UiOps.MaxFileSizeForLexer);
2763 end;
2764
2765
2766 procedure DoLexerDetect(const AFilename: string;
2767 out Lexer: TecSyntAnalyzer;
2768 out LexerLite: TATLiteLexer;
2769 out LexerName: string;
2770 AChooseFunc: TecLexerChooseFunc);
2771 begin
2772 LexerName:= '';
2773 Lexer:= nil;
2774 LexerLite:= nil;
2775 if AFilename='' then exit;
2776
2777 if IsFileTooBigForLexer(AFilename) then
2778 begin
2779 LexerLite:= AppManagerLite.FindLexerByFilename(AFilename);
2780 end
2781 else
2782 begin
2783 Lexer:= DoLexerDetectByFilenameOrContent(AFilename, AChooseFunc);
2784 if Lexer=nil then
2785 LexerLite:= AppManagerLite.FindLexerByFilename(AFilename);
2786 end;
2787
2788 if Assigned(Lexer) then
2789 LexerName:= Lexer.LexerName
2790 else
2791 if Assigned(LexerLite) then
2792 LexerName:= LexerLite.LexerName+msgLiteLexerSuffix;
2793 end;
2794
2795
2796 procedure FixFormPositionToDesktop(F: TForm);
2797 const
2798 cReservePixels = 100;
2799 var
2800 R: TRect;
2801 begin
2802 R:= Screen.DesktopRect;
2803 F.Left:= Max(F.Left, R.Left);
2804 F.Left:= Min(F.Left, R.Right-F.Width);
2805 F.Top:= Min(F.Top, R.Bottom-cReservePixels);
2806 end;
2807
2808 procedure FixRectPositionToDesktop(var F: TRect);
2809 const
2810 cReservePixels = 200;
2811 var
2812 R: TRect;
2813 w, h: integer;
2814 begin
2815 w:= F.Width;
2816 h:= F.Height;
2817
2818 R:= Screen.DesktopRect;
2819 F.Left:= Max(F.Left, R.Left);
2820 F.Left:= Min(F.Left, R.Right-F.Width);
2821 F.Top:= Min(F.Top, R.Bottom-cReservePixels);
2822
2823 F.Right:= F.Left+w;
2824 F.Bottom:= F.Top+h;
2825 end;
2826
2827 procedure EditorClear(Ed: TATSynEdit);
2828 begin
2829 Ed.Strings.Clear;
2830 Ed.Strings.ActionAddFakeLineIfNeeded;
2831 Ed.DoCaretSingle(0, 0);
2832 Ed.Update(true);
2833 Ed.Modified:= false;
2834 end;
2835
2836 { TAppManagerThread }
2837
2838 procedure TAppManagerThread.Execute;
2839 begin
2840 //AppManager.AllowedThreadId:= Self.ThreadID;
2841 AppLoadLexers;
2842 //AppManager.AllowedThreadId:= 0;
2843 end;
2844
2845 { TAppCommandInfo }
2846
CommaStrnull2847 function TAppCommandInfo.CommaStr: string;
2848 begin
2849 if ItemModule='' then
2850 Result:= ''
2851 else
2852 begin
2853 Result:= ItemModule+','+ItemProc;
2854 if ItemProcParam<>'' then
2855 Result+= ','+ItemProcParam;
2856 end;
2857 end;
2858
2859 { TAppFileProps }
2860
2861 class operator TAppFileProps.= (const a, b: TAppFileProps): boolean;
2862 begin
2863 Result:=
2864 (a.Exists=b.Exists) and
2865 (a.Size=b.Size) and
2866 (a.Age=b.Age);
2867 end;
2868
2869
2870 { TAppKeyValues }
2871
2872 procedure TAppKeyValues.Add(const AKey, AValue: string);
2873 var
2874 Item: TAppKeyValue;
2875 begin
2876 Item:= TAppKeyValue.Create;
2877 Item.Key:= AKey;
2878 Item.Value:= AValue;
2879 inherited Add(Item);
2880 end;
2881
GetValuenull2882 function TAppKeyValues.GetValue(const AKey, ADefValue: string): string;
2883 var
2884 Item: TAppKeyValue;
2885 i: integer;
2886 begin
2887 for i:= 0 to Count-1 do
2888 begin
2889 Item:= TAppKeyValue(Items[i]);
2890 if Item.Key=AKey then
2891 exit(Item.Value);
2892 end;
2893 Result:= ADefValue;
2894 end;
2895
2896 function AppScale(AValue: integer): integer; inline;
2897 begin
2898 Result:= AValue * UiOps.Scale div 100;
2899 end;
2900
2901 function AppScaleFont(AValue: integer): integer;
2902 begin
2903 if UiOps.ScaleFont=0 then
2904 Result:= AppScale(AValue)
2905 else
2906 Result:= AValue * UiOps.ScaleFont div 100;
2907 end;
2908
2909 procedure DoMenuitemEllipsis(c: TMenuItem);
2910 var
2911 s: string;
2912 begin
2913 if c=nil then exit;
2914 s:= c.Caption;
2915 while (s<>'') and (s[Length(s)]='.') do
2916 SetLength(s, Length(s)-1);
2917 c.Caption:= s+'...';
2918 end;
2919
2920
2921 function RemoveWindowsStreamSuffix(const fn: string): string;
2922 var
2923 PosSlash, PosColon: integer;
2924 begin
2925 Result:= fn;
2926 {$ifdef windows}
2927 PosSlash:= RPos('\', fn);
2928 if PosSlash=0 then exit;
2929 PosColon:= Pos(':', fn, PosSlash);
2930 if PosColon>0 then
2931 SetLength(Result, PosColon-1);
2932 {$endif}
2933 end;
2934
2935 procedure AppGetFileProps(const FileName: string; out P: TAppFileProps);
2936 var
2937 Rec: TSearchRec;
2938 begin
2939 P.Inited:= true;
2940 P.Exists:= FindFirst(RemoveWindowsStreamSuffix(FileName), faAnyFile, Rec)=0;
2941 if P.Exists then
2942 begin
2943 P.Size:= Rec.Size;
2944 P.Age:= Rec.Time;
2945 FindClose(Rec);
2946 end
2947 else
2948 begin
2949 P.Size:= 0;
2950 P.Age:= 0;
2951 end;
2952 end;
2953
2954 procedure AppUpdateWatcherFrames;
2955 var
2956 i: integer;
2957 begin
2958 //function is called in IdleTimer, so just exit if watcher thread is busy,
2959 //we will try this again on next timer tick
2960 if AppEventWatcher.WaitFor(1)<>wrSignaled then exit;
2961
2962 AppEventLister.ResetEvent;
2963 try
2964 for i:= 0 to AppFrameListDeleting.Count-1 do
2965 TObject(AppFrameListDeleting[i]).Free;
2966 AppFrameListDeleting.Clear;
2967
2968 AppFrameList2.Assign(AppFrameList1);
2969 finally
2970 AppEventLister.SetEvent;
2971 end;
2972 end;
2973
2974
2975 class function TPluginHelper.CommandCategory(Cmd: integer): TAppCommandCategory;
2976 var
2977 N: integer;
2978 begin
2979 case Cmd of
2980 cmdFirstPluginCommand..cmdLastPluginCommand:
2981 begin
2982 Result:= categ_Plugin;
2983 N:= Cmd-cmdFirstPluginCommand;
2984 if N<AppCommandList.Count then
2985 begin
2986 if TAppCommandInfo(AppCommandList[N]).ItemFromApi then
2987 Result:= categ_PluginSub;
2988 end
2989 else
2990 //we are here when e.g. in plugin Macros user deletes a macro,
2991 //so code detects category of deleted command-code
2992 Result:= categ_PluginSub;
2993 end;
2994 cmdFirstLexerCommand..cmdLastLexerCommand:
2995 Result:= categ_Lexer;
2996 cmdFirstFileCommand..cmdLastFileCommand:
2997 Result:= categ_OpenedFile;
2998 cmdFirstRecentCommand..cmdLastRecentCommand:
2999 Result:= categ_RecentFile;
3000 else
3001 Result:= categ_Normal;
3002 end;
3003 end;
3004
3005 class function TPluginHelper.CommandHasConfigurableHotkey(Cmd: integer): boolean;
3006 begin
3007 Result:= CommandCategory(Cmd) in [categ_Normal, categ_Plugin, categ_PluginSub];
3008 end;
3009
3010 procedure InitBasicCommandLineOptions;
3011 var
3012 S: string;
3013 i: integer;
3014 begin
3015 for i:= 1 to ParamCount do
3016 begin
3017 S:= ParamStr(i);
3018
3019 if S='-n' then
3020 begin
3021 AppAlwaysNewInstance:= true;
3022 Continue;
3023 end;
3024
3025 if SBeginsWith(S, '-id=') then
3026 begin
3027 Delete(S, 1, Length('-id='));
3028 if S<>'' then
3029 AppServerId:= S;
3030 Continue;
3031 end;
3032 end;
3033 end;
3034
3035 class function TPluginHelper.EventIsUsed(AEvent: TAppPyEvent): boolean;
3036 var
3037 NPlugin: integer;
3038 Plugin: TAppEventInfo;
3039 begin
3040 Result:= false;
3041 for NPlugin:= 0 to AppEventList.Count-1 do
3042 begin
3043 Plugin:= TAppEventInfo(AppEventList[NPlugin]);
3044 if AEvent in Plugin.ItemEvents then
3045 exit(true);
3046 end;
3047 end;
3048
3049 class procedure TPluginHelper.EventStringToEventData(const AEventStr: string;
3050 out AEvents: TAppPyEvents;
3051 out AEventsPrior: TAppPyEventsPrior;
3052 out AEventsLazy: TAppPyEventsLazy);
3053 const
3054 MaxPriority = 4;
3055 var
3056 Sep: TATStringSeparator;
3057 S: string;
3058 event: TAppPyEvent;
3059 nPrior: byte;
3060 bLazy: boolean;
3061 begin
3062 AEvents:= [];
3063 FillChar(AEventsPrior, SizeOf(AEventsPrior), 0);
3064 FillChar(AEventsLazy, SizeOf(AEventsLazy), 0);
3065
3066 Sep.Init(AEventStr);
3067 while Sep.GetItemStr(S) do
3068 begin
3069 nPrior:= 0;
3070 while S[Length(S)]='+' do
3071 begin
3072 Inc(nPrior);
3073 SetLength(S, Length(S)-1);
3074 end;
3075
3076 if nPrior>MaxPriority then
3077 nPrior:= MaxPriority;
3078
3079 bLazy:= false;
3080 if S[Length(S)]='~' then
3081 begin
3082 bLazy:= true;
3083 SetLength(S, Length(S)-1);
3084 end;
3085
3086 for event in TAppPyEvent do
3087 if S=cAppPyEvent[event] then
3088 begin
3089 Include(AEvents, event);
3090 AEventsPrior[event]:= nPrior;
3091 AEventsLazy[event]:= bLazy;
3092 Break
3093 end;
3094 end;
3095 end;
3096
3097
3098 class procedure TPluginHelper.EventsUpdate(const AModuleName, AEventStr, ALexerStr, AKeyStr: string);
3099 var
3100 EventItem: TAppEventInfo;
3101 i: integer;
3102 begin
3103 //find index of plugin (get first empty index if not listed)
3104 EventItem:= nil;
3105 for i:= 0 to AppEventList.Count-1 do
3106 with TAppEventInfo(AppEventList[i]) do
3107 if (ItemModule=AModuleName) then
3108 begin
3109 EventItem:= TAppEventInfo(AppEventList[i]);
3110 Break
3111 end;
3112
3113 if EventItem=nil then
3114 begin
3115 EventItem:= TAppEventInfo.Create;
3116 AppEventList.Add(EventItem);
3117 end;
3118
3119 //update item
3120 with EventItem do
3121 begin
3122 if ItemModule='' then
3123 ItemModule:= AModuleName;
3124 EventStringToEventData(AEventStr, ItemEvents, ItemEventsPrior, ItemEventsLazy);
3125 ItemLexers:= ALexerStr;
3126 ItemKeys:= AKeyStr;
3127 end;
3128
3129 EventsMaxPrioritiesUpdate;
3130 end;
3131
3132 class procedure TPluginHelper.CommandsClearButKeepApiItems;
3133 var
3134 i: integer;
3135 begin
3136 for i:= AppCommandList.Count-1 downto 0 do
3137 with TAppCommandInfo(AppCommandList[i]) do
3138 if (ItemModule<>'') and (not ItemFromApi) then
3139 AppCommandList.Delete(i);
3140 end;
3141
3142 class procedure TPluginHelper.EventsMaxPrioritiesUpdate;
3143 var
3144 ev: TAppPyEvent;
3145 Plugin: TAppEventInfo;
3146 Value, i: integer;
3147 begin
3148 for ev in TAppPyEvent do
3149 begin
3150 Value:= -1;
3151 for i:= 0 to AppEventList.Count-1 do
3152 begin
3153 Plugin:= TAppEventInfo(AppEventList[i]);
3154 if ev in Plugin.ItemEvents then
3155 Value:= Max(Value, Plugin.ItemEventsPrior[ev]);
3156 end;
3157 AppEventsMaxPriorities[ev]:= Value;
3158 end;
3159 end;
3160
3161
3162 function IsOsFullPath(const S: string): boolean;
3163 begin
3164 {$ifdef windows}
3165 //'D:\path'
3166 //'\\UNCpath'
3167 Result:=
3168 (Length(S)>2) and
3169 ((S[2]=':') or ((S[1]='\') and (S[2]='\')));
3170 {$else}
3171 Result:= SBeginsWith(S, '/');
3172 {$endif}
3173 end;
3174
3175
3176 procedure AppOnLexerLoaded(Sender: TObject; ALexer: TecSyntAnalyzer);
3177 var
3178 fn_ops: string;
3179 begin
3180 //load *.cuda-lexops
3181 fn_ops:= GetAppLexerOpsFilename(ALexer.LexerName);
3182 if FileExists(fn_ops) then
3183 DoLoadLexerStylesFromFile_JsonLexerOps(ALexer, fn_ops, UiOps.LexerThemes);
3184 end;
3185
3186 procedure AppLoadLexers;
3187 var
3188 cfg: TJsonConfig;
3189 SErrorLines: string;
3190 SErrorItem: string;
3191 Sep: TATStringSeparator;
3192 {
3193 var
3194 NCountNormal, NCountLite: integer;
3195 NTickNormal, NTickLite: QWord;
3196 }
3197 begin
3198 //must read UiOps.LexerThemes here, AppLoadLexers runs in a thread
3199 //before loading all options, and we need this option already
3200 cfg:= TJsonConfig.Create(nil);
3201 try
3202 try
3203 cfg.Filename:= AppFile_OptionsUser;
3204 UiOps.LexerThemes:= cfg.GetValue('ui_lexer_themes', UiOps.LexerThemes);
3205 except
3206 end;
3207 finally
3208 cfg.Free;
3209 end;
3210
3211 //1) load lite lexers
3212 //NTickLite:= GetTickCount64;
3213
3214 AppManagerLite.Clear;
3215 AppManagerLite.LoadFromDir(AppDir_LexersLite);
3216
3217 {
3218 NTickLite:= GetTickCount64-NTickLite;
3219 NCountLite:= AppManagerLite.LexerCount;
3220 if NCountLite=0 then
3221 MsgLogConsole(Format(msgCannotFindLexers, [AppDir_LexersLite]));
3222 }
3223
3224 //2) load EControl lexers
3225 //NTickNormal:= GetTickCount64;
3226
3227 AppManager.OnLexerLoaded:= @AppOnLexerLoaded;
3228 AppManager.InitLibrary(AppDir_Lexers, SErrorLines);
3229
3230 if SErrorLines<>'' then
3231 begin
3232 Sep.Init(SErrorLines, #10);
3233 while Sep.GetItemStr(SErrorItem) do
3234 MsgLogConsole('NOTE: '+SErrorItem);
3235 end;
3236
3237 {
3238 NTickNormal:= GetTickCount64-NTickNormal;
3239 NCountNormal:= AppManager.LexerCount;
3240 if NCountNormal=0 then
3241 MsgLogConsole(Format(msgCannotFindLexers, [AppDir_Lexers]));
3242 }
3243 end;
3244
3245
3246 function LiteLexer_GetStyleHash(const AStyleName: string): integer;
3247 var
3248 iStyle: TAppThemeStyleId;
3249 begin
3250 Result:= -1;
3251 for iStyle:= Low(iStyle) to High(iStyle) do
3252 if SameStr(AStyleName, AppTheme.Styles[iStyle].DisplayName) then
3253 exit(Ord(iStyle));
3254 end;
3255
3256 procedure LiteLexer_ApplyStyle(AStyleHash: integer; var APart: TATLinePart);
3257 var
3258 st: TecSyntaxFormat;
3259 begin
3260 if AStyleHash<0 then exit;
3261 st:= AppTheme.Styles[TAppThemeStyleId(AStyleHash)];
3262 ApplyPartStyleFromEcontrolStyle(APart, st);
3263 end;
3264
3265 function IsDefaultSessionActive: boolean;
3266 begin
3267 Result:=
3268 (AppSessionName='') or
3269 (AppSessionName=cAppSessionDefault);
3270 end;
3271
3272
3273 function AppConfigKeyForBookmarks(Ed: TATSynEdit): string;
3274 begin
3275 if Ed.FileName<>'' then
3276 Result:= '/bookmarks/'+SMaskFilenameSlashes(AppCollapseHomeDirInFilename(Ed.FileName))
3277 else
3278 Result:= '';
3279 end;
3280
3281 function AppDiskGetFreeSpace(const fn: string): Int64;
3282 begin
3283 {$ifdef linux}
3284 //this crashes on FreeBSD 12 x64
3285 exit(SysUtils.DiskFree(SysUtils.AddDisk(ExtractFileDir(fn))));
3286 {$endif}
3287
3288 {$ifdef windows}
3289 exit(SysUtils.DiskFree(SysUtils.GetDriveIDFromLetter(ExtractFileDrive(fn))));
3290 {$endif}
3291
3292 //cannot detect
3293 exit(-1);
3294 end;
3295
3296 procedure AppDiskCheckFreeSpace(const fn: string);
3297 var
3298 NSpace: Int64;
3299 begin
3300 if UiOps.CheckLowDiskSpace<=0 then exit;
3301 repeat
3302 NSpace:= AppDiskGetFreeSpace(fn);
3303 if NSpace<0 then exit; //cannot detect free space
3304 if NSpace>=UiOps.CheckLowDiskSpace then exit;
3305 if MsgBox(
3306 Format(msgErrorLowDiskSpaceMb, [NSpace div (1024*1024)]),
3307 MB_RETRYCANCEL or MB_ICONWARNING) = ID_CANCEL then exit;
3308 until false;
3309 end;
3310
3311 function AppKeyIsAllowedAsCustomHotkey(Key: Word; Shift: TShiftState): boolean;
3312 begin
3313 Result:= true;
3314
3315 //don't allow to reassign system keys: Alt/Ctrl/Shift/Win
3316 if (Key=VK_MENU) or
3317 (Key=VK_LMENU) or
3318 (Key=VK_RMENU) or
3319 (Key=VK_CONTROL) or
3320 (Key=VK_LCONTROL) or
3321 (Key=VK_RCONTROL) or
3322 (Key=VK_SHIFT) or
3323 (Key=VK_LSHIFT) or
3324 (Key=VK_RSHIFT) or
3325 (Key=VK_LWIN) or
3326 (Key=VK_RWIN) then
3327 exit(false);
3328
3329 //don't allow to reassign these
3330 if (Key in [VK_SPACE, VK_RETURN, VK_TAB, VK_BACK]) and (Shift=[]) then
3331 exit(false);
3332 end;
3333
3334 initialization
3335
3336 InitDirs;
3337 InitEditorOps(EditorOps);
3338 InitUiOps(UiOps);
3339 InitBasicCommandLineOptions;
3340
3341 AppConsoleQueue:= TAppConsoleQueue.Create;
3342 AppCommandsDelayed:= TAppCommandsDelayed.Create;
3343 AppCommandList:= TFPList.Create;
3344 AppEventList:= TFPList.Create;
3345 AppTreeHelpers:= TFPList.Create;
3346
3347 AppKeymapMain:= TATKeymap.Create;
3348 InitKeymapFull(AppKeymapMain);
3349 Keymap_AddCudatextItems(AppKeymapMain);
3350
3351 AppKeymapLexers:= TStringList.Create;
3352 AppKeymapLexers.Sorted:= true;
3353 AppKeymapLexers.OwnsObjects:= true;
3354
3355 FillChar(AppEventsMaxPriorities, SizeOf(AppEventsMaxPriorities), 0);
3356 FillChar(AppBookmarkSetup, SizeOf(AppBookmarkSetup), 0);
3357 AppBookmarkImagelist:= TImageList.Create(nil);
3358
3359 AppShortcutEscape:= ShortCut(VK_ESCAPE, []);
3360 AppShortcutShiftTab:= ShortCut(VK_TAB, [ssShift]);
3361
3362 Mouse.DragImmediate:= false;
3363 Mouse.DragThreshold:= 12;
3364
3365 AppConfig_Detect:= TAppKeyValues.Create;
3366 AppConfig_DetectLine:= TAppKeyValues.Create;
3367 AppConfig_PGroups:= TAppKeyValues.Create;
3368
3369 ////detection of Shell files
3370 ////disabled: it detects Python files with shebang
3371 //AppConfig_DetectLine_Keys.Add('\#!.+');
3372 //AppConfig_DetectLine_Values.Add('Bash script');
3373
3374 //detection of XML
3375 AppConfig_DetectLine.Add('<\?xml .+', 'XML');
3376
3377 AppFrameList1:= TFPList.Create;
3378 AppFrameList2:= TFPList.Create;
3379 AppFrameListDeleting:= TFPList.Create;
3380 AppEventLister:= TEvent.Create(nil, true, true, '');
3381 AppEventWatcher:= TEvent.Create(nil, true, true, '');
3382
3383 AppApiFlatTheme:= ATFlatTheme;
3384 AppListRecents:= TStringList.Create;
3385
3386 ATSynEdit_Commands.cCommand_GotoDefinition:= cmd_GotoDefinition;
3387
3388 AppManager:= TecLexerList.Create(nil);
3389 AppManagerLite:= TATLiteLexers.Create(nil);
3390 AppManagerLite.OnGetStyleHash:= @LiteLexer_GetStyleHash;
3391 AppManagerLite.OnApplyStyle:= @LiteLexer_ApplyStyle;
3392 AppManagerThread:= TAppManagerThread.Create(false);
3393
3394 finalization
3395
3396 FreeAndNil(AppManagerThread);
3397 FreeAndNil(AppManagerLite);
3398 FreeAndNil(AppManager);
3399
3400 FreeAndNil(AppListRecents);
3401 FreeAndNil(AppEventWatcher);
3402 FreeAndNil(AppEventLister);
3403 FreeAndNil(AppFrameListDeleting);
3404 FreeAndNil(AppFrameList2);
3405 FreeAndNil(AppFrameList1);
3406
3407 FreeAndNil(AppConfig_PGroups);
3408 FreeAndNil(AppConfig_DetectLine);
3409 FreeAndNil(AppConfig_Detect);
3410 FreeAndNil(AppKeymapLexers);
3411 FreeAndNil(AppKeymapMain);
3412 FreeAndNil(AppBookmarkImagelist);
3413
3414 FreeAndNil(AppTreeHelpers);
3415 FreeAndNil(AppEventList);
3416 FreeAndNil(AppCommandList);
3417 FreeAndNil(AppConsoleQueue);
3418 FreeAndNil(AppCommandsDelayed);
3419
3420 end.
3421
3422