@oh-my-pi/pi-utils 15.11.2 → 15.11.3

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.
@@ -7,3 +7,24 @@ export declare function setDefaultTabWidth(width: number): void;
7
7
  * Visible tab width in columns for `file` (from `.editorconfig` + default), or the default when `file` is omitted.
8
8
  */
9
9
  export declare function getIndentation(file?: string | null, projectDir?: string | null): number;
10
+ /**
11
+ * `.editorconfig`-derived formatting options for an LSP `textDocument/formatting` request.
12
+ *
13
+ * Both fields are absent when the resolved `.editorconfig` chain does not pin them, so callers
14
+ * can layer their own fallbacks (content sniffing, project defaults) underneath. Returned values
15
+ * are clamped to {@link MIN_TAB_WIDTH}..{@link MAX_TAB_WIDTH} for parity with {@link getIndentation}.
16
+ */
17
+ export interface EditorConfigFormatting {
18
+ /** Effective indent width in columns, from `indent_size` or `tab_width`. */
19
+ tabSize?: number;
20
+ /** `true` for `indent_style = space`, `false` for `indent_style = tab` (or `indent_size = tab`). */
21
+ insertSpaces?: boolean;
22
+ }
23
+ /**
24
+ * Resolve `.editorconfig` formatting hints for `file` without falling back to any default.
25
+ *
26
+ * Used by the LSP format-on-write path so a missing `.editorconfig` declaration falls through
27
+ * to caller-provided defaults instead of clobbering the file with the renderer's display
28
+ * `defaultTabWidth` (issue #2329).
29
+ */
30
+ export declare function getEditorConfigFormatting(file?: string | null, projectDir?: string | null): EditorConfigFormatting;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-utils",
4
- "version": "15.11.2",
4
+ "version": "15.11.3",
5
5
  "description": "Shared utilities for pi packages",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -31,7 +31,7 @@
31
31
  "fmt": "biome format --write ."
32
32
  },
33
33
  "dependencies": {
34
- "@oh-my-pi/pi-natives": "15.11.2",
34
+ "@oh-my-pi/pi-natives": "15.11.3",
35
35
  "beautiful-mermaid": "^1.1.3",
36
36
  "handlebars": "^4.7.9",
37
37
  "winston": "^3.19.0",
@@ -340,3 +340,66 @@ export function getIndentation(file?: string | null, projectDir?: string | null)
340
340
  indentationCache.set(absKey, clamped);
341
341
  return clamped;
342
342
  }
343
+
344
+ /**
345
+ * `.editorconfig`-derived formatting options for an LSP `textDocument/formatting` request.
346
+ *
347
+ * Both fields are absent when the resolved `.editorconfig` chain does not pin them, so callers
348
+ * can layer their own fallbacks (content sniffing, project defaults) underneath. Returned values
349
+ * are clamped to {@link MIN_TAB_WIDTH}..{@link MAX_TAB_WIDTH} for parity with {@link getIndentation}.
350
+ */
351
+ export interface EditorConfigFormatting {
352
+ /** Effective indent width in columns, from `indent_size` or `tab_width`. */
353
+ tabSize?: number;
354
+ /** `true` for `indent_style = space`, `false` for `indent_style = tab` (or `indent_size = tab`). */
355
+ insertSpaces?: boolean;
356
+ }
357
+
358
+ /**
359
+ * Resolve `.editorconfig` formatting hints for `file` without falling back to any default.
360
+ *
361
+ * Used by the LSP format-on-write path so a missing `.editorconfig` declaration falls through
362
+ * to caller-provided defaults instead of clobbering the file with the renderer's display
363
+ * `defaultTabWidth` (issue #2329).
364
+ */
365
+ export function getEditorConfigFormatting(file?: string | null, projectDir?: string | null): EditorConfigFormatting {
366
+ if (file === undefined || file === null || file === "") {
367
+ return {};
368
+ }
369
+
370
+ const cwd = projectDir ?? process.cwd();
371
+ const absoluteFile = resolveFilePath(cwd, file);
372
+
373
+ // Same NAME_MAX guard as `getIndentation`: editorconfig discovery is
374
+ // best-effort and must never escape as `ENAMETOOLONG` from a renderer's
375
+ // stray gibberish path.
376
+ if (hasOverlongPathComponent(absoluteFile)) {
377
+ return {};
378
+ }
379
+
380
+ const match = resolveEditorConfigMatch(absoluteFile);
381
+ if (match === undefined) {
382
+ return {};
383
+ }
384
+
385
+ const result: EditorConfigFormatting = {};
386
+
387
+ if (match.indentSize?.kind === "spaces") {
388
+ result.tabSize = clampTabWidth(match.indentSize.n);
389
+ } else if (match.tabWidth !== undefined) {
390
+ result.tabSize = clampTabWidth(match.tabWidth);
391
+ }
392
+
393
+ if (match.indentStyle === IndentStyle.Space) {
394
+ result.insertSpaces = true;
395
+ } else if (match.indentStyle === IndentStyle.Tab || match.indentSize?.kind === "tab") {
396
+ result.insertSpaces = false;
397
+ } else if (match.indentSize?.kind === "spaces") {
398
+ // `indent_size = <n>` without an explicit `indent_style` is universally
399
+ // read as "indent with N spaces" — both VSCode and Sublime infer
400
+ // `indent_style = space` in that case.
401
+ result.insertSpaces = true;
402
+ }
403
+
404
+ return result;
405
+ }