@fresh-editor/fresh-editor 0.1.87 → 0.1.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -336,18 +336,11 @@ function applyGitLogHighlighting(): void {
336
336
 
337
337
  // Highlight section header
338
338
  if (line === editor.t("panel.commits_header")) {
339
- editor.addOverlay(
340
- bufferId,
341
- "gitlog",
342
- lineStart,
343
- lineEnd,
344
- colors.header[0],
345
- colors.header[1],
346
- colors.header[2],
347
- true, // underline
348
- true, // bold
349
- false // italic
350
- );
339
+ editor.addOverlay(bufferId, "gitlog", lineStart, lineEnd, {
340
+ fg: colors.header,
341
+ underline: true,
342
+ bold: true,
343
+ });
351
344
  byteOffset += line.length + 1;
352
345
  continue;
353
346
  }
@@ -364,35 +357,19 @@ function applyGitLogHighlighting(): void {
364
357
 
365
358
  // Highlight entire line if cursor is on it (using selected color with underline)
366
359
  if (isCurrentLine) {
367
- editor.addOverlay(
368
- bufferId,
369
- "gitlog",
370
- lineStart,
371
- lineEnd,
372
- colors.selected[0],
373
- colors.selected[1],
374
- colors.selected[2],
375
- true, // underline to make it visible
376
- true, // bold
377
- false // italic
378
- );
360
+ editor.addOverlay(bufferId, "gitlog", lineStart, lineEnd, {
361
+ fg: colors.selected,
362
+ underline: true,
363
+ bold: true,
364
+ });
379
365
  }
380
366
 
381
367
  // Parse the line format: "shortHash (author, relativeDate) subject [refs]"
382
368
  // Highlight hash (first 7+ chars until space)
383
369
  const hashEnd = commit.shortHash.length;
384
- editor.addOverlay(
385
- bufferId,
386
- "gitlog",
387
- lineStart,
388
- lineStart + hashEnd,
389
- colors.hash[0],
390
- colors.hash[1],
391
- colors.hash[2],
392
- false, // underline
393
- false, // bold
394
- false // italic
395
- );
370
+ editor.addOverlay(bufferId, "gitlog", lineStart, lineStart + hashEnd, {
371
+ fg: colors.hash,
372
+ });
396
373
 
397
374
  // Highlight author name (inside parentheses)
398
375
  const authorPattern = "(" + commit.author + ",";
@@ -400,18 +377,9 @@ function applyGitLogHighlighting(): void {
400
377
  if (authorStartInLine >= 0) {
401
378
  const authorStart = lineStart + authorStartInLine + 1; // skip "("
402
379
  const authorEnd = authorStart + commit.author.length;
403
- editor.addOverlay(
404
- bufferId,
405
- "gitlog",
406
- authorStart,
407
- authorEnd,
408
- colors.author[0],
409
- colors.author[1],
410
- colors.author[2],
411
- false, // underline
412
- false, // bold
413
- false // italic
414
- );
380
+ editor.addOverlay(bufferId, "gitlog", authorStart, authorEnd, {
381
+ fg: colors.author,
382
+ });
415
383
  }
416
384
 
417
385
  // Highlight relative date
@@ -420,18 +388,9 @@ function applyGitLogHighlighting(): void {
420
388
  if (dateStartInLine >= 0) {
421
389
  const dateStart = lineStart + dateStartInLine + 2; // skip ", "
422
390
  const dateEnd = dateStart + commit.relativeDate.length;
423
- editor.addOverlay(
424
- bufferId,
425
- "gitlog",
426
- dateStart,
427
- dateEnd,
428
- colors.date[0],
429
- colors.date[1],
430
- colors.date[2],
431
- false, // underline
432
- false, // bold
433
- false // italic
434
- );
391
+ editor.addOverlay(bufferId, "gitlog", dateStart, dateEnd, {
392
+ fg: colors.date,
393
+ });
435
394
  }
436
395
 
437
396
  // Highlight refs (branches/tags) at end of line if present
@@ -449,18 +408,10 @@ function applyGitLogHighlighting(): void {
449
408
  refColor = colors.remote;
450
409
  }
451
410
 
452
- editor.addOverlay(
453
- bufferId,
454
- "gitlog",
455
- refsStart,
456
- refsEnd,
457
- refColor[0],
458
- refColor[1],
459
- refColor[2],
460
- false, // underline
461
- true, // bold (make refs stand out)
462
- false // italic
463
- );
411
+ editor.addOverlay(bufferId, "gitlog", refsStart, refsEnd, {
412
+ fg: refColor,
413
+ bold: true,
414
+ });
464
415
  }
465
416
  }
466
417
 
@@ -621,112 +572,52 @@ function applyCommitDetailHighlighting(): void {
621
572
 
622
573
  // Highlight diff additions (green)
623
574
  if (line.startsWith("+") && !line.startsWith("+++")) {
624
- editor.addOverlay(
625
- bufferId,
626
- "gitdetail",
627
- lineStart,
628
- lineEnd,
629
- colors.diffAdd[0],
630
- colors.diffAdd[1],
631
- colors.diffAdd[2],
632
- false, // underline
633
- false, // bold
634
- false // italic
635
- );
575
+ editor.addOverlay(bufferId, "gitdetail", lineStart, lineEnd, {
576
+ fg: colors.diffAdd,
577
+ });
636
578
  }
637
579
  // Highlight diff deletions (red)
638
580
  else if (line.startsWith("-") && !line.startsWith("---")) {
639
- editor.addOverlay(
640
- bufferId,
641
- "gitdetail",
642
- lineStart,
643
- lineEnd,
644
- colors.diffDel[0],
645
- colors.diffDel[1],
646
- colors.diffDel[2],
647
- false, // underline
648
- false, // bold
649
- false // italic
650
- );
581
+ editor.addOverlay(bufferId, "gitdetail", lineStart, lineEnd, {
582
+ fg: colors.diffDel,
583
+ });
651
584
  }
652
585
  // Highlight hunk headers (cyan/blue)
653
586
  else if (line.startsWith("@@")) {
654
- editor.addOverlay(
655
- bufferId,
656
- "gitdetail",
657
- lineStart,
658
- lineEnd,
659
- colors.diffHunk[0],
660
- colors.diffHunk[1],
661
- colors.diffHunk[2],
662
- false, // underline
663
- true, // bold
664
- false // italic
665
- );
587
+ editor.addOverlay(bufferId, "gitdetail", lineStart, lineEnd, {
588
+ fg: colors.diffHunk,
589
+ bold: true,
590
+ });
666
591
  }
667
592
  // Highlight commit hash in "commit <hash>" line (git show format)
668
593
  else if (line.startsWith("commit ")) {
669
594
  const hashMatch = line.match(/^commit ([a-f0-9]+)/);
670
595
  if (hashMatch) {
671
596
  const hashStart = lineStart + 7; // "commit " is 7 chars
672
- editor.addOverlay(
673
- bufferId,
674
- "gitdetail",
675
- hashStart,
676
- hashStart + hashMatch[1].length,
677
- colors.hash[0],
678
- colors.hash[1],
679
- colors.hash[2],
680
- false, // underline
681
- true, // bold
682
- false // italic
683
- );
597
+ editor.addOverlay(bufferId, "gitdetail", hashStart, hashStart + hashMatch[1].length, {
598
+ fg: colors.hash,
599
+ bold: true,
600
+ });
684
601
  }
685
602
  }
686
603
  // Highlight author line
687
604
  else if (line.startsWith("Author:")) {
688
- editor.addOverlay(
689
- bufferId,
690
- "gitdetail",
691
- lineStart + 8, // "Author: " is 8 chars
692
- lineEnd,
693
- colors.author[0],
694
- colors.author[1],
695
- colors.author[2],
696
- false, // underline
697
- false, // bold
698
- false // italic
699
- );
605
+ editor.addOverlay(bufferId, "gitdetail", lineStart + 8, lineEnd, {
606
+ fg: colors.author,
607
+ });
700
608
  }
701
609
  // Highlight date line
702
610
  else if (line.startsWith("Date:")) {
703
- editor.addOverlay(
704
- bufferId,
705
- "gitdetail",
706
- lineStart + 6, // "Date: " is 6 chars (with trailing spaces it's 8)
707
- lineEnd,
708
- colors.date[0],
709
- colors.date[1],
710
- colors.date[2],
711
- false, // underline
712
- false, // bold
713
- false // italic
714
- );
611
+ editor.addOverlay(bufferId, "gitdetail", lineStart + 6, lineEnd, {
612
+ fg: colors.date,
613
+ });
715
614
  }
716
615
  // Highlight diff file headers
717
616
  else if (line.startsWith("diff --git")) {
718
- editor.addOverlay(
719
- bufferId,
720
- "gitdetail",
721
- lineStart,
722
- lineEnd,
723
- colors.header[0],
724
- colors.header[1],
725
- colors.header[2],
726
- false, // underline
727
- true, // bold
728
- false // italic
729
- );
617
+ editor.addOverlay(bufferId, "gitdetail", lineStart, lineEnd, {
618
+ fg: colors.header,
619
+ bold: true,
620
+ });
730
621
  }
731
622
 
732
623
  byteOffset += line.length + 1;
@@ -1080,7 +971,10 @@ function applyFileViewHighlighting(bufferId: number, content: string, filePath:
1080
971
  inMultilineComment = true;
1081
972
  }
1082
973
  if (inMultilineComment) {
1083
- editor.addOverlay(bufferId, "syntax", lineStart, lineStart + line.length, colors.syntaxComment[0], colors.syntaxComment[1], colors.syntaxComment[2], false, false, true);
974
+ editor.addOverlay(bufferId, "syntax", lineStart, lineStart + line.length, {
975
+ fg: colors.syntaxComment,
976
+ italic: true,
977
+ });
1084
978
  if (line.includes("*/")) {
1085
979
  inMultilineComment = false;
1086
980
  }
@@ -1099,7 +993,9 @@ function applyFileViewHighlighting(bufferId: number, content: string, filePath:
1099
993
  }
1100
994
  }
1101
995
  if (inMultilineString) {
1102
- editor.addOverlay(bufferId, "syntax", lineStart, lineStart + line.length, colors.syntaxString[0], colors.syntaxString[1], colors.syntaxString[2], false, false, false);
996
+ editor.addOverlay(bufferId, "syntax", lineStart, lineStart + line.length, {
997
+ fg: colors.syntaxString,
998
+ });
1103
999
  byteOffset += line.length + 1;
1104
1000
  continue;
1105
1001
  }
@@ -1113,12 +1009,14 @@ function applyFileViewHighlighting(bufferId: number, content: string, filePath:
1113
1009
  }
1114
1010
 
1115
1011
  if (commentStart >= 0) {
1116
- editor.addOverlay(bufferId, "syntax", lineStart + commentStart, lineStart + line.length, colors.syntaxComment[0], colors.syntaxComment[1], colors.syntaxComment[2], false, false, true);
1012
+ editor.addOverlay(bufferId, "syntax", lineStart + commentStart, lineStart + line.length, {
1013
+ fg: colors.syntaxComment,
1014
+ italic: true,
1015
+ });
1117
1016
  }
1118
1017
 
1119
1018
  // String highlighting (simple: find "..." and '...')
1120
1019
  let i = 0;
1121
- let stringCount = 0;
1122
1020
  while (i < line.length) {
1123
1021
  const ch = line[i];
1124
1022
  if (ch === '"' || ch === "'") {
@@ -1132,7 +1030,9 @@ function applyFileViewHighlighting(bufferId: number, content: string, filePath:
1132
1030
  if (i < line.length) i++; // Include closing quote
1133
1031
  const end = i;
1134
1032
  if (commentStart < 0 || start < commentStart) {
1135
- editor.addOverlay(bufferId, "syntax", lineStart + start, lineStart + end, colors.syntaxString[0], colors.syntaxString[1], colors.syntaxString[2], false, false, false);
1033
+ editor.addOverlay(bufferId, "syntax", lineStart + start, lineStart + end, {
1034
+ fg: colors.syntaxString,
1035
+ });
1136
1036
  }
1137
1037
  } else {
1138
1038
  i++;
@@ -1142,25 +1042,30 @@ function applyFileViewHighlighting(bufferId: number, content: string, filePath:
1142
1042
  // Keyword highlighting
1143
1043
  for (const keyword of keywords) {
1144
1044
  const regex = new RegExp(`\\b${keyword}\\b`, "g");
1145
- let match;
1045
+ let match: RegExpExecArray | null;
1146
1046
  while ((match = regex.exec(line)) !== null) {
1147
1047
  const kwStart = match.index;
1148
1048
  const kwEnd = kwStart + keyword.length;
1149
1049
  // Don't highlight if inside comment
1150
1050
  if (commentStart < 0 || kwStart < commentStart) {
1151
- editor.addOverlay(bufferId, "syntax", lineStart + kwStart, lineStart + kwEnd, colors.syntaxKeyword[0], colors.syntaxKeyword[1], colors.syntaxKeyword[2], false, true, false);
1051
+ editor.addOverlay(bufferId, "syntax", lineStart + kwStart, lineStart + kwEnd, {
1052
+ fg: colors.syntaxKeyword,
1053
+ bold: true,
1054
+ });
1152
1055
  }
1153
1056
  }
1154
1057
  }
1155
1058
 
1156
1059
  // Number highlighting
1157
1060
  const numberRegex = /\b\d+(\.\d+)?\b/g;
1158
- let numMatch;
1061
+ let numMatch: RegExpExecArray | null;
1159
1062
  while ((numMatch = numberRegex.exec(line)) !== null) {
1160
1063
  const numStart = numMatch.index;
1161
1064
  const numEnd = numStart + numMatch[0].length;
1162
1065
  if (commentStart < 0 || numStart < commentStart) {
1163
- editor.addOverlay(bufferId, "syntax", lineStart + numStart, lineStart + numEnd, colors.syntaxNumber[0], colors.syntaxNumber[1], colors.syntaxNumber[2], false, false, false);
1066
+ editor.addOverlay(bufferId, "syntax", lineStart + numStart, lineStart + numEnd, {
1067
+ fg: colors.syntaxNumber,
1068
+ });
1164
1069
  }
1165
1070
  }
1166
1071
 
@@ -1335,62 +1335,26 @@ export class Finder<T> {
1335
1335
 
1336
1336
  // Highlight current line if it's an item line
1337
1337
  if (isCurrentLine && isItemLine && line.trim() !== "") {
1338
- this.editor.addOverlay(
1339
- bufferId,
1340
- namespace,
1341
- lineStart,
1342
- lineEnd,
1343
- colors.selected[0],
1344
- colors.selected[1],
1345
- colors.selected[2],
1346
- false,
1347
- false,
1348
- false,
1349
- undefined,
1350
- undefined,
1351
- undefined,
1352
- true
1353
- );
1338
+ this.editor.addOverlay(bufferId, namespace, lineStart, lineEnd, {
1339
+ fg: colors.selected,
1340
+ extendToLineEnd: true,
1341
+ });
1354
1342
  }
1355
1343
 
1356
1344
  // Title line
1357
1345
  if (lineNumber === 1) {
1358
- this.editor.addOverlay(
1359
- bufferId,
1360
- namespace,
1361
- lineStart,
1362
- lineEnd,
1363
- colors.title[0],
1364
- colors.title[1],
1365
- colors.title[2],
1366
- false,
1367
- true,
1368
- false,
1369
- undefined,
1370
- undefined,
1371
- undefined,
1372
- false
1373
- );
1346
+ this.editor.addOverlay(bufferId, namespace, lineStart, lineEnd, {
1347
+ fg: colors.title,
1348
+ bold: true,
1349
+ });
1374
1350
  }
1375
1351
 
1376
1352
  // File header (ends with : but isn't title)
1377
1353
  if (line.endsWith(":") && lineNumber > 1 && !line.startsWith(" ")) {
1378
- this.editor.addOverlay(
1379
- bufferId,
1380
- namespace,
1381
- lineStart,
1382
- lineEnd,
1383
- colors.fileHeader[0],
1384
- colors.fileHeader[1],
1385
- colors.fileHeader[2],
1386
- false,
1387
- true,
1388
- false,
1389
- undefined,
1390
- undefined,
1391
- undefined,
1392
- false
1393
- );
1354
+ this.editor.addOverlay(bufferId, namespace, lineStart, lineEnd, {
1355
+ fg: colors.fileHeader,
1356
+ bold: true,
1357
+ });
1394
1358
  }
1395
1359
 
1396
1360
  // Severity icon highlighting
@@ -1415,42 +1379,17 @@ export class Finder<T> {
1415
1379
  color = colors.hint;
1416
1380
  }
1417
1381
 
1418
- this.editor.addOverlay(
1419
- bufferId,
1420
- namespace,
1421
- lineStart,
1422
- iconEnd,
1423
- color[0],
1424
- color[1],
1425
- color[2],
1426
- false,
1427
- true,
1428
- false,
1429
- undefined,
1430
- undefined,
1431
- undefined,
1432
- false
1433
- );
1382
+ this.editor.addOverlay(bufferId, namespace, lineStart, iconEnd, {
1383
+ fg: color,
1384
+ bold: true,
1385
+ });
1434
1386
  }
1435
1387
 
1436
1388
  // Help line (dimmed)
1437
1389
  if (line.startsWith("Enter:") || line.includes("|")) {
1438
- this.editor.addOverlay(
1439
- bufferId,
1440
- namespace,
1441
- lineStart,
1442
- lineEnd,
1443
- colors.help[0],
1444
- colors.help[1],
1445
- colors.help[2],
1446
- false,
1447
- false,
1448
- false,
1449
- undefined,
1450
- undefined,
1451
- undefined,
1452
- false
1453
- );
1390
+ this.editor.addOverlay(bufferId, namespace, lineStart, lineEnd, {
1391
+ fg: colors.help,
1392
+ });
1454
1393
  }
1455
1394
 
1456
1395
  byteOffset += line.length + 1;
@@ -349,6 +349,16 @@ type FileExplorerDecoration = {
349
349
  */
350
350
  priority: number;
351
351
  };
352
+ type FormatterPackConfig = {
353
+ /**
354
+ * Command to run (e.g., "prettier", "rustfmt")
355
+ */
356
+ command: string;
357
+ /**
358
+ * Arguments to pass to the formatter
359
+ */
360
+ args: Array<string>;
361
+ };
352
362
  type BackgroundProcessResult = {
353
363
  /**
354
364
  * Unique process ID for later reference
@@ -523,6 +533,54 @@ type CreateVirtualBufferOptions = {
523
533
  */
524
534
  entries?: Array<TextPropertyEntry>;
525
535
  };
536
+ type LanguagePackConfig = {
537
+ /**
538
+ * Comment prefix for line comments (e.g., "//" or "#")
539
+ */
540
+ commentPrefix: string | null;
541
+ /**
542
+ * Block comment start marker (e.g., slash-star)
543
+ */
544
+ blockCommentStart: string | null;
545
+ /**
546
+ * Block comment end marker (e.g., star-slash)
547
+ */
548
+ blockCommentEnd: string | null;
549
+ /**
550
+ * Whether to use tabs instead of spaces for indentation
551
+ */
552
+ useTabs: boolean | null;
553
+ /**
554
+ * Tab size (number of spaces per tab level)
555
+ */
556
+ tabSize: number | null;
557
+ /**
558
+ * Whether auto-indent is enabled
559
+ */
560
+ autoIndent: boolean | null;
561
+ /**
562
+ * Formatter configuration
563
+ */
564
+ formatter: FormatterPackConfig | null;
565
+ };
566
+ type LspServerPackConfig = {
567
+ /**
568
+ * Command to start the LSP server
569
+ */
570
+ command: string;
571
+ /**
572
+ * Arguments to pass to the command
573
+ */
574
+ args: Array<string>;
575
+ /**
576
+ * Whether to auto-start the server when a matching file is opened
577
+ */
578
+ autoStart: boolean | null;
579
+ /**
580
+ * LSP initialization options
581
+ */
582
+ initializationOptions: Record<string, unknown> | null;
583
+ };
526
584
  type SpawnResult = {
527
585
  /**
528
586
  * Complete stdout as string
@@ -774,6 +832,29 @@ interface EditorAPI {
774
832
  */
775
833
  reloadConfig(): void;
776
834
  /**
835
+ * Reload theme registry from disk
836
+ * Call this after installing theme packages or saving new themes
837
+ */
838
+ reloadThemes(): void;
839
+ /**
840
+ * Register a TextMate grammar file for a language
841
+ * The grammar will be pending until reload_grammars() is called
842
+ */
843
+ registerGrammar(language: string, grammarPath: string, extensions: string[]): boolean;
844
+ /**
845
+ * Register language configuration (comment prefix, indentation, formatter)
846
+ */
847
+ registerLanguageConfig(language: string, config: LanguagePackConfig): boolean;
848
+ /**
849
+ * Register an LSP server for a language
850
+ */
851
+ registerLspServer(language: string, config: LspServerPackConfig): boolean;
852
+ /**
853
+ * Reload the grammar registry to apply registered grammars
854
+ * Call this after registering one or more grammars
855
+ */
856
+ reloadGrammars(): void;
857
+ /**
777
858
  * Get config directory path
778
859
  */
779
860
  getConfigDir(): string;
@@ -835,9 +916,23 @@ interface EditorAPI {
835
916
  */
836
917
  getHighlights(bufferId: number, start: number, end: number): Promise<TsHighlightSpan[]>;
837
918
  /**
838
- * Add an overlay with styling
919
+ * Add an overlay with styling options
920
+ *
921
+ * Colors can be specified as RGB arrays `[r, g, b]` or theme key strings.
922
+ * Theme keys are resolved at render time, so overlays update with theme changes.
923
+ *
924
+ * Theme key examples: "ui.status_bar_fg", "editor.selection_bg", "syntax.keyword"
925
+ *
926
+ * Example usage in TypeScript:
927
+ * ```typescript
928
+ * editor.addOverlay(bufferId, "my-namespace", 0, 10, {
929
+ * fg: "syntax.keyword", // theme key
930
+ * bg: [40, 40, 50], // RGB array
931
+ * bold: true,
932
+ * });
933
+ * ```
839
934
  */
840
- addOverlay(bufferId: number, namespace: string, start: number, end: number, r: number, g: number, b: number, underline?: boolean, bold?: boolean, italic?: boolean, bgR?: number, bgG?: number, bgB?: number, extendToLineEnd?: boolean): boolean;
935
+ addOverlay(bufferId: number, namespace: string, start: number, end: number, options: Record<string, unknown>): boolean;
841
936
  /**
842
937
  * Clear all overlays in a namespace
843
938
  */
@@ -867,10 +962,8 @@ interface EditorAPI {
867
962
  clearViewTransform(bufferId: number, splitId: number | null): boolean;
868
963
  /**
869
964
  * Set file explorer decorations for a namespace
870
- *
871
- * Uses typed Vec<FileExplorerDecoration> - serde validates field names at runtime
872
965
  */
873
- setFileExplorerDecorations(namespace: string, decorations: FileExplorerDecoration[]): boolean;
966
+ setFileExplorerDecorations(namespace: string, decorations: Record<string, unknown>[]): boolean;
874
967
  /**
875
968
  * Clear file explorer decorations for a namespace
876
969
  */
@@ -999,6 +1092,11 @@ interface EditorAPI {
999
1092
  */
1000
1093
  disableLspForLanguage(language: string): boolean;
1001
1094
  /**
1095
+ * Set the workspace root URI for a specific language's LSP server
1096
+ * This allows plugins to specify project roots (e.g., directory containing .csproj)
1097
+ */
1098
+ setLspRootUri(language: string, uri: string): boolean;
1099
+ /**
1002
1100
  * Get all diagnostics from LSP
1003
1101
  */
1004
1102
  getAllDiagnostics(): JsDiagnostic[];
@@ -1064,4 +1162,25 @@ interface EditorAPI {
1064
1162
  * Get the current locale
1065
1163
  */
1066
1164
  getCurrentLocale(): string;
1165
+ /**
1166
+ * Load a plugin from a file path (async)
1167
+ */
1168
+ loadPlugin(path: string): Promise<boolean>;
1169
+ /**
1170
+ * Unload a plugin by name (async)
1171
+ */
1172
+ unloadPlugin(name: string): Promise<boolean>;
1173
+ /**
1174
+ * Reload a plugin by name (async)
1175
+ */
1176
+ reloadPlugin(name: string): Promise<boolean>;
1177
+ /**
1178
+ * List all loaded plugins (async)
1179
+ * Returns array of { name: string, path: string, enabled: boolean }
1180
+ */
1181
+ listPlugins(): Promise<Array<{
1182
+ name: string;
1183
+ path: string;
1184
+ enabled: boolean;
1185
+ }>>;
1067
1186
  }