@jbearak/sight 0.8.4 → 0.9.0

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.
@@ -52,15 +52,15 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "@jbearak/sight",
55
- version: "0.8.4",
55
+ version: "0.9.0",
56
56
  type: "module",
57
57
  workspaces: [
58
58
  "client"
59
59
  ],
60
- description: "Language Server Protocol implementation for Stata",
60
+ description: "A static analyzer and language server for the Stata statistical programming language",
61
61
  repository: {
62
62
  type: "git",
63
- url: "https://github.com/jbearak/sight.git"
63
+ url: "git+https://github.com/jbearak/sight.git"
64
64
  },
65
65
  bugs: {
66
66
  url: "https://github.com/jbearak/sight/issues"
@@ -79,8 +79,8 @@ var init_package = __esm(() => {
79
79
  "build:npm": "bun run build:bundle && npm run validate:npm",
80
80
  "validate:npm": "node dist/sight-server.js --version && echo 'NPM build validation passed'",
81
81
  prepublishOnly: "npm run build:npm",
82
- "publish:npm": "npm publish --ignore-scripts --access public",
83
- "publish:dry-run": "npm publish --dry-run --access public",
82
+ "publish:npm": "npm run build:npm && npm publish --ignore-scripts --access public",
83
+ "publish:dry-run": "npm run build:npm && npm publish --dry-run --ignore-scripts --access public",
84
84
  "install:binary": "bun scripts/install.ts",
85
85
  "uninstall:binary": "bun scripts/uninstall.ts",
86
86
  watch: "tsc --watch",
@@ -913,6 +913,7 @@ var init_schema = __esm(() => {
913
913
  "undefinedVariable",
914
914
  "styleWarnings",
915
915
  "malformedOperator",
916
+ "spacedCompoundOperator",
916
917
  "invalidOperatorSequence",
917
918
  "cStyleLogicalInControlFlow",
918
919
  "mixedLogicalOperators"
@@ -2145,7 +2146,8 @@ function isFileCommand(command) {
2145
2146
  return FILE_COMMANDS.has(command);
2146
2147
  }
2147
2148
  function isPathDirective(directive) {
2148
- return PATH_DIRECTIVES.has(directive.toLowerCase());
2149
+ const normalized = directive.trim().replace(/^sight:\s*/, "@lsp-");
2150
+ return PATH_DIRECTIVES.has(normalized);
2149
2151
  }
2150
2152
  function hasStataExtension(filename) {
2151
2153
  const lower = filename.toLowerCase();
@@ -2431,6 +2433,7 @@ var init_file_path_utils = __esm(() => {
2431
2433
  ]);
2432
2434
  PATH_DIRECTIVES = new Set([
2433
2435
  "@lsp-done-by",
2436
+ "@lsp-run-by",
2434
2437
  "@lsp-included-by",
2435
2438
  "@lsp-do",
2436
2439
  "@lsp-run",
@@ -11109,7 +11112,7 @@ var require_server = __commonJS((exports) => {
11109
11112
 
11110
11113
  // node_modules/vscode-languageserver/lib/node/files.js
11111
11114
  var require_files = __commonJS((exports) => {
11112
- var __filename = "/Users/jmb/.codex/worktrees/3573/sight/node_modules/vscode-languageserver/lib/node/files.js";
11115
+ var __filename = "/home/runner/work/sight/sight/node_modules/vscode-languageserver/lib/node/files.js";
11113
11116
  Object.defineProperty(exports, "__esModule", { value: true });
11114
11117
  exports.resolveModulePath = exports.FileSystem = exports.resolveGlobalYarnPath = exports.resolveGlobalNodePath = exports.resolve = exports.uriToFilePath = undefined;
11115
11118
  var url = __require("url");
@@ -11676,8 +11679,99 @@ function undefined_symbol_data_fields(diagnostic) {
11676
11679
  };
11677
11680
  }
11678
11681
 
11682
+ // src/utils/diagnostic-code-description.ts
11683
+ function diagnostic_code_anchor(code) {
11684
+ if (code === undefined || code === null) {
11685
+ return null;
11686
+ }
11687
+ const value = String(code).trim();
11688
+ if (value.length === 0) {
11689
+ return null;
11690
+ }
11691
+ const cached = anchor_cache.get(value);
11692
+ if (cached !== undefined) {
11693
+ return cached;
11694
+ }
11695
+ const anchor = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
11696
+ anchor_cache.set(value, anchor);
11697
+ return anchor;
11698
+ }
11699
+ function diagnostic_code_description(code) {
11700
+ const anchor = diagnostic_code_anchor(code);
11701
+ if (!anchor) {
11702
+ return;
11703
+ }
11704
+ return {
11705
+ href: `${DIAGNOSTICS_DOCUMENTATION_URL}#${anchor}`
11706
+ };
11707
+ }
11708
+ function diagnostic_code_description_fields(code) {
11709
+ const codeDescription = diagnostic_code_description(code);
11710
+ return codeDescription ? { codeDescription } : {};
11711
+ }
11712
+ var DIAGNOSTICS_DOCUMENTATION_URL = "https://github.com/jbearak/sight/blob/main/docs/diagnostics.md", anchor_cache;
11713
+ var init_diagnostic_code_description = __esm(() => {
11714
+ anchor_cache = new Map;
11715
+ });
11716
+
11679
11717
  // src/types/index.ts
11680
- var init_types = () => {};
11718
+ var LexerErrorCode, ParseErrorCode, StataDiagnosticCode;
11719
+ var init_types = __esm(() => {
11720
+ ((LexerErrorCode2) => {
11721
+ LexerErrorCode2["UNBALANCED_QUOTES"] = "UNBALANCED_QUOTES";
11722
+ LexerErrorCode2["UNBALANCED_BLOCK_COMMENT"] = "UNBALANCED_BLOCK_COMMENT";
11723
+ LexerErrorCode2["UNTERMINATED_STATEMENT"] = "UNTERMINATED_STATEMENT";
11724
+ LexerErrorCode2["CONTINUATION_NO_SPACE"] = "CONTINUATION_NO_SPACE";
11725
+ LexerErrorCode2["BLOCK_COMMENT_IN_STAR_COMMENT"] = "BLOCK_COMMENT_IN_STAR_COMMENT";
11726
+ })(LexerErrorCode ||= {});
11727
+ ((ParseErrorCode2) => {
11728
+ ParseErrorCode2["SYNTAX_ERROR"] = "SYNTAX_ERROR";
11729
+ ParseErrorCode2["BRACE_ELSE_SAME_LINE"] = "BRACE_ELSE_SAME_LINE";
11730
+ ParseErrorCode2["BRACE_NOT_ALONE"] = "BRACE_NOT_ALONE";
11731
+ ParseErrorCode2["MISSING_PROGRAM_END"] = "MISSING_PROGRAM_END";
11732
+ ParseErrorCode2["OPEN_BRACE_ALONE"] = "OPEN_BRACE_ALONE";
11733
+ ParseErrorCode2["UNCLOSED_BLOCK"] = "UNCLOSED_BLOCK";
11734
+ ParseErrorCode2["CODE_AFTER_OPEN_BRACE"] = "CODE_AFTER_OPEN_BRACE";
11735
+ ParseErrorCode2["FORVALUES_SYNTAX"] = "FORVALUES_SYNTAX";
11736
+ ParseErrorCode2["REDUNDANT_MACRO_SUFFIX"] = "REDUNDANT_MACRO_SUFFIX";
11737
+ ParseErrorCode2["MISSING_EXPRESSION_AFTER_EQUALS"] = "MISSING_EXPRESSION_AFTER_EQUALS";
11738
+ ParseErrorCode2["UNBALANCED_PARENTHESES"] = "UNBALANCED_PARENTHESES";
11739
+ ParseErrorCode2["ORPHAN_CLOSE_BRACE"] = "ORPHAN_CLOSE_BRACE";
11740
+ ParseErrorCode2["STRAY_TOKEN_IN_CONDITION"] = "STRAY_TOKEN_IN_CONDITION";
11741
+ ParseErrorCode2["SPLIT_LITERAL_IN_CONDITION"] = "SPLIT_LITERAL_IN_CONDITION";
11742
+ })(ParseErrorCode ||= {});
11743
+ ((StataDiagnosticCode2) => {
11744
+ StataDiagnosticCode2["UNBALANCED_QUOTES"] = "UNBALANCED_QUOTES";
11745
+ StataDiagnosticCode2["UNBALANCED_BLOCK_COMMENT"] = "UNBALANCED_BLOCK_COMMENT";
11746
+ StataDiagnosticCode2["UNTERMINATED_STATEMENT"] = "UNTERMINATED_STATEMENT";
11747
+ StataDiagnosticCode2["CONTINUATION_NO_SPACE"] = "CONTINUATION_NO_SPACE";
11748
+ StataDiagnosticCode2["BLOCK_COMMENT_IN_STAR_COMMENT"] = "BLOCK_COMMENT_IN_STAR_COMMENT";
11749
+ StataDiagnosticCode2["UNDEFINED_MACRO"] = "UNDEFINED_MACRO";
11750
+ StataDiagnosticCode2["UNDEFINED_VARIABLE"] = "UNDEFINED_VARIABLE";
11751
+ StataDiagnosticCode2["OUT_OF_SCOPE_SYMBOL"] = "OUT_OF_SCOPE_SYMBOL";
11752
+ StataDiagnosticCode2["MISSING_VARIABLE_NAME"] = "MISSING_VARIABLE_NAME";
11753
+ StataDiagnosticCode2["SYNTAX_ERROR"] = "SYNTAX_ERROR";
11754
+ StataDiagnosticCode2["BRACE_ELSE_SAME_LINE"] = "BRACE_ELSE_SAME_LINE";
11755
+ StataDiagnosticCode2["BRACE_NOT_ALONE"] = "BRACE_NOT_ALONE";
11756
+ StataDiagnosticCode2["MISSING_PROGRAM_END"] = "MISSING_PROGRAM_END";
11757
+ StataDiagnosticCode2["OPEN_BRACE_ALONE"] = "OPEN_BRACE_ALONE";
11758
+ StataDiagnosticCode2["UNCLOSED_BLOCK"] = "UNCLOSED_BLOCK";
11759
+ StataDiagnosticCode2["CODE_AFTER_OPEN_BRACE"] = "CODE_AFTER_OPEN_BRACE";
11760
+ StataDiagnosticCode2["FORVALUES_SYNTAX"] = "FORVALUES_SYNTAX";
11761
+ StataDiagnosticCode2["REDUNDANT_MACRO_SUFFIX"] = "REDUNDANT_MACRO_SUFFIX";
11762
+ StataDiagnosticCode2["INVALID_MACRO_CHAR"] = "INVALID_MACRO_CHAR";
11763
+ StataDiagnosticCode2["UNNECESSARY_INDENTATION"] = "UNNECESSARY_INDENTATION";
11764
+ StataDiagnosticCode2["MISSING_INDENTATION"] = "MISSING_INDENTATION";
11765
+ StataDiagnosticCode2["MALFORMED_OPERATOR"] = "MALFORMED_OPERATOR";
11766
+ StataDiagnosticCode2["INVALID_OPERATOR_SEQUENCE"] = "INVALID_OPERATOR_SEQUENCE";
11767
+ StataDiagnosticCode2["CSTYLE_LOGICAL_IN_CONTROL_FLOW"] = "CSTYLE_LOGICAL_IN_CONTROL_FLOW";
11768
+ StataDiagnosticCode2["MIXED_LOGICAL_OPERATORS"] = "MIXED_LOGICAL_OPERATORS";
11769
+ StataDiagnosticCode2["SPACED_COMPOUND_OPERATOR"] = "SPACED_COMPOUND_OPERATOR";
11770
+ StataDiagnosticCode2["PATH_CASE_MISMATCH"] = "PATH_CASE_MISMATCH";
11771
+ StataDiagnosticCode2["CROSS_FILE_MISSING_FILE"] = "CROSS_FILE_MISSING_FILE";
11772
+ StataDiagnosticCode2["CROSS_FILE_TRUNCATED"] = "CROSS_FILE_TRUNCATED";
11773
+ })(StataDiagnosticCode ||= {});
11774
+ });
11681
11775
 
11682
11776
  // src/lexer/index.ts
11683
11777
  class StataLexer {
@@ -11739,7 +11833,7 @@ class StataLexer {
11739
11833
  const lexerError = {
11740
11834
  message: `Unexpected lexer error: ${error}`,
11741
11835
  range: this.makeRange(startLine, startColumn, this.line, this.column),
11742
- code: 1001 /* UNBALANCED_QUOTES */
11836
+ code: "UNBALANCED_QUOTES" /* UNBALANCED_QUOTES */
11743
11837
  };
11744
11838
  this.errors.push(lexerError);
11745
11839
  this.advance();
@@ -11820,10 +11914,17 @@ class StataLexer {
11820
11914
  }
11821
11915
  if (my_char === "/" && my_pos + 1 < this.source.length && this.source[my_pos + 1] === "*") {
11822
11916
  my_pos += 2;
11823
- while (my_pos + 1 < this.source.length) {
11917
+ let my_depth = 1;
11918
+ while (my_pos + 1 < this.source.length && my_depth > 0) {
11919
+ if (this.source[my_pos] === "/" && this.source[my_pos + 1] === "*") {
11920
+ my_depth++;
11921
+ my_pos += 2;
11922
+ continue;
11923
+ }
11824
11924
  if (this.source[my_pos] === "*" && this.source[my_pos + 1] === "/") {
11925
+ my_depth--;
11825
11926
  my_pos += 2;
11826
- break;
11927
+ continue;
11827
11928
  }
11828
11929
  if (this.source[my_pos] === `
11829
11930
  `) {
@@ -11831,7 +11932,7 @@ class StataLexer {
11831
11932
  }
11832
11933
  my_pos++;
11833
11934
  }
11834
- if (my_pos + 1 >= this.source.length) {
11935
+ if (my_depth > 0) {
11835
11936
  return true;
11836
11937
  }
11837
11938
  continue;
@@ -12192,19 +12293,12 @@ class StataLexer {
12192
12293
  const my_block_start_column = this.column;
12193
12294
  this.advance();
12194
12295
  this.advance();
12195
- while (!this.isAtEnd()) {
12196
- if (this.peek() === "*" && this.peekNext() === "/") {
12197
- this.advance();
12198
- this.advance();
12199
- break;
12200
- }
12201
- this.advance();
12202
- }
12296
+ this.consumeBlockCommentBody();
12203
12297
  if (this.line !== my_block_start_line) {
12204
12298
  const my_error = {
12205
12299
  message: "Block comment `/* */` inside star comment causes" + " multi-line comment behavior — subsequent lines until" + " `*/` will be treated as comment by Stata",
12206
12300
  range: this.makeRange(my_block_start_line, my_block_start_column, this.line, this.column),
12207
- code: 1005 /* BLOCK_COMMENT_IN_STAR_COMMENT */
12301
+ code: "BLOCK_COMMENT_IN_STAR_COMMENT" /* BLOCK_COMMENT_IN_STAR_COMMENT */
12208
12302
  };
12209
12303
  this.errors.push(my_error);
12210
12304
  }
@@ -12235,14 +12329,7 @@ class StataLexer {
12235
12329
  };
12236
12330
  }
12237
12331
  scanBlockComment(startLine, startColumn) {
12238
- while (!this.isAtEnd()) {
12239
- if (this.peek() === "*" && this.peekNext() === "/") {
12240
- this.advance();
12241
- this.advance();
12242
- break;
12243
- }
12244
- this.advance();
12245
- }
12332
+ this.consumeBlockCommentBody();
12246
12333
  const value = this.source.substring(this.position_to_offset(startLine, startColumn), this.position);
12247
12334
  return {
12248
12335
  type: "COMMENT_BLOCK",
@@ -12250,6 +12337,24 @@ class StataLexer {
12250
12337
  range: this.makeRange(startLine, startColumn, this.line, this.column)
12251
12338
  };
12252
12339
  }
12340
+ consumeBlockCommentBody() {
12341
+ let depth = 1;
12342
+ while (!this.isAtEnd() && depth > 0) {
12343
+ if (this.peek() === "/" && this.peekNext() === "*") {
12344
+ this.advance();
12345
+ this.advance();
12346
+ depth++;
12347
+ continue;
12348
+ }
12349
+ if (this.peek() === "*" && this.peekNext() === "/") {
12350
+ this.advance();
12351
+ this.advance();
12352
+ depth--;
12353
+ continue;
12354
+ }
12355
+ this.advance();
12356
+ }
12357
+ }
12253
12358
  scanDelimitDirective(startLine, startColumn) {
12254
12359
  while (this.peek() === " " || this.peek() === "\t") {
12255
12360
  this.advance();
@@ -12291,7 +12396,7 @@ class StataLexer {
12291
12396
  const error = {
12292
12397
  message: "Unclosed string literal",
12293
12398
  range: this.makeRange(startLine, startColumn, this.line, this.column + 1),
12294
- code: 1001 /* UNBALANCED_QUOTES */
12399
+ code: "UNBALANCED_QUOTES" /* UNBALANCED_QUOTES */
12295
12400
  };
12296
12401
  this.errors.push(error);
12297
12402
  break;
@@ -12407,7 +12512,7 @@ class StataLexer {
12407
12512
  const error = {
12408
12513
  message: "Unclosed string literal",
12409
12514
  range: this.makeRange(startLine, startColumn, this.line, this.column),
12410
- code: 1001 /* UNBALANCED_QUOTES */
12515
+ code: "UNBALANCED_QUOTES" /* UNBALANCED_QUOTES */
12411
12516
  };
12412
12517
  this.errors.push(error);
12413
12518
  }
@@ -12437,7 +12542,7 @@ class StataLexer {
12437
12542
  const error = {
12438
12543
  message: "Unclosed string literal",
12439
12544
  range: this.makeRange(startLine, startColumn, this.line, this.column + 1),
12440
- code: 1001 /* UNBALANCED_QUOTES */
12545
+ code: "UNBALANCED_QUOTES" /* UNBALANCED_QUOTES */
12441
12546
  };
12442
12547
  this.errors.push(error);
12443
12548
  break;
@@ -12554,7 +12659,7 @@ class StataLexer {
12554
12659
  const error = {
12555
12660
  message: "Unclosed string literal",
12556
12661
  range: this.makeRange(startLine, startColumn, this.line, this.column),
12557
- code: 1001 /* UNBALANCED_QUOTES */
12662
+ code: "UNBALANCED_QUOTES" /* UNBALANCED_QUOTES */
12558
12663
  };
12559
12664
  this.errors.push(error);
12560
12665
  }
@@ -12581,7 +12686,7 @@ class StataLexer {
12581
12686
  const my_error = {
12582
12687
  message: "Incomplete macro expression: expected closing quote",
12583
12688
  range: this.makeRange(startLine, startColumn, this.line, this.column),
12584
- code: 1001 /* UNBALANCED_QUOTES */
12689
+ code: "UNBALANCED_QUOTES" /* UNBALANCED_QUOTES */
12585
12690
  };
12586
12691
  this.errors.push(my_error);
12587
12692
  break;
@@ -12602,7 +12707,7 @@ class StataLexer {
12602
12707
  const my_error = {
12603
12708
  message: "Incomplete macro expression: expected closing quote",
12604
12709
  range: this.makeRange(startLine, startColumn, this.line, this.column),
12605
- code: 1001 /* UNBALANCED_QUOTES */
12710
+ code: "UNBALANCED_QUOTES" /* UNBALANCED_QUOTES */
12606
12711
  };
12607
12712
  this.errors.push(my_error);
12608
12713
  }
@@ -12625,7 +12730,7 @@ class StataLexer {
12625
12730
  const my_error = {
12626
12731
  message: "Incomplete macro expression: expected '}' or closing quote",
12627
12732
  range: this.makeRange(startLine, startColumn, this.line, this.column),
12628
- code: 1001 /* UNBALANCED_QUOTES */
12733
+ code: "UNBALANCED_QUOTES" /* UNBALANCED_QUOTES */
12629
12734
  };
12630
12735
  this.errors.push(my_error);
12631
12736
  break;
@@ -12660,7 +12765,7 @@ class StataLexer {
12660
12765
  const my_error = {
12661
12766
  message: "Incomplete macro expression: expected '}' or closing quote",
12662
12767
  range: this.makeRange(startLine, startColumn, this.line, this.column),
12663
- code: 1001 /* UNBALANCED_QUOTES */
12768
+ code: "UNBALANCED_QUOTES" /* UNBALANCED_QUOTES */
12664
12769
  };
12665
12770
  this.errors.push(my_error);
12666
12771
  }
@@ -13017,7 +13122,7 @@ var init_parser = __esm(() => {
13017
13122
  this.errors.push({
13018
13123
  message: "open brace must be on the same line as the condition",
13019
13124
  range: brace_token.range,
13020
- code: 3004 /* OPEN_BRACE_ALONE */
13125
+ code: "OPEN_BRACE_ALONE" /* OPEN_BRACE_ALONE */
13021
13126
  });
13022
13127
  let brace_depth = 1;
13023
13128
  while (!this.isAtEnd() && brace_depth > 0) {
@@ -13035,7 +13140,7 @@ var init_parser = __esm(() => {
13035
13140
  this.errors.push({
13036
13141
  message: "unexpected closing brace - no matching opening brace",
13037
13142
  range: brace_token.range,
13038
- code: 3012 /* ORPHAN_CLOSE_BRACE */
13143
+ code: "ORPHAN_CLOSE_BRACE" /* ORPHAN_CLOSE_BRACE */
13039
13144
  });
13040
13145
  this.pending_trivia = leading_trivia;
13041
13146
  return null;
@@ -13214,11 +13319,11 @@ var init_parser = __esm(() => {
13214
13319
  parseMacroDefinition() {
13215
13320
  const scopeToken = this.advance();
13216
13321
  const scope = scopeToken.value;
13217
- this.skipTrivia();
13322
+ this.skipMacroDefinitionTrivia();
13218
13323
  let prefixOp;
13219
13324
  if (this.check("OPERATOR") && (this.peek().value === "++" || this.peek().value === "--")) {
13220
13325
  prefixOp = this.advance().value;
13221
- this.skipTrivia();
13326
+ this.skipMacroDefinitionTrivia();
13222
13327
  }
13223
13328
  if (!this.check("WORD")) {
13224
13329
  this.addError("Expected macro name", this.peek().range);
@@ -13226,13 +13331,13 @@ var init_parser = __esm(() => {
13226
13331
  }
13227
13332
  const nameToken = this.advance();
13228
13333
  const macroName = nameToken.value;
13229
- this.skipTrivia();
13334
+ this.skipMacroDefinitionTrivia();
13230
13335
  if (!prefixOp && this.check("OPERATOR") && (this.peek().value === "++" || this.peek().value === "--")) {
13231
13336
  const suffixOp = this.peek().value;
13232
13337
  this.errors.push({
13233
13338
  message: `Macro ${suffixOp} suffix is likely a mistake. Did you mean ${suffixOp}${macroName}?`,
13234
13339
  range: this.makeRange(nameToken.range.start, this.peek().range.end),
13235
- code: 3009 /* REDUNDANT_MACRO_SUFFIX */
13340
+ code: "REDUNDANT_MACRO_SUFFIX" /* REDUNDANT_MACRO_SUFFIX */
13236
13341
  });
13237
13342
  }
13238
13343
  if (this.check("COLON")) {
@@ -13243,7 +13348,7 @@ var init_parser = __esm(() => {
13243
13348
  has_equals = true;
13244
13349
  this.advance();
13245
13350
  }
13246
- this.skipTrivia();
13351
+ this.skipMacroDefinitionTrivia();
13247
13352
  let value = prefixOp || "";
13248
13353
  const value_start_pos = this.current;
13249
13354
  let paren_depth = 0;
@@ -13261,7 +13366,7 @@ var init_parser = __esm(() => {
13261
13366
  } else if (token.type === "RPAREN") {
13262
13367
  paren_depth--;
13263
13368
  if (paren_depth < 0) {
13264
- this.addError("Unbalanced parentheses: unexpected closing parenthesis", token.range, 3011 /* UNBALANCED_PARENTHESES */);
13369
+ this.addError("Unbalanced parentheses: unexpected closing parenthesis", token.range, "UNBALANCED_PARENTHESES" /* UNBALANCED_PARENTHESES */);
13265
13370
  paren_depth = 0;
13266
13371
  }
13267
13372
  }
@@ -13269,11 +13374,11 @@ var init_parser = __esm(() => {
13269
13374
  }
13270
13375
  if (paren_depth > 0) {
13271
13376
  const end_pos = this.current > 0 ? this.previous().range : this.peek().range;
13272
- this.addError("Unbalanced parentheses: missing closing parenthesis", end_pos, 3011 /* UNBALANCED_PARENTHESES */);
13377
+ this.addError("Unbalanced parentheses: missing closing parenthesis", end_pos, "UNBALANCED_PARENTHESES" /* UNBALANCED_PARENTHESES */);
13273
13378
  }
13274
13379
  if (has_equals && value.trim() === "" && !prefixOp) {
13275
13380
  const equals_pos = value_start_pos > 0 ? this.tokens[value_start_pos - 1].range : this.peek().range;
13276
- this.addError("Missing expression after equals sign", equals_pos, 3010 /* MISSING_EXPRESSION_AFTER_EQUALS */);
13381
+ this.addError("Missing expression after equals sign", equals_pos, "MISSING_EXPRESSION_AFTER_EQUALS" /* MISSING_EXPRESSION_AFTER_EQUALS */);
13277
13382
  }
13278
13383
  return {
13279
13384
  type: "macro_def",
@@ -13286,15 +13391,21 @@ var init_parser = __esm(() => {
13286
13391
  }
13287
13392
  parse_extended_macro_def(scopeToken, scope, macroName) {
13288
13393
  this.advance();
13289
- this.skipTrivia();
13394
+ this.skipMacroDefinitionTrivia();
13290
13395
  if (!this.check("WORD")) {
13291
13396
  this.addError("Expected function name after colon", this.peek().range);
13292
13397
  throw new Error("Missing function name");
13293
13398
  }
13294
13399
  const function_name = this.advance().value;
13295
- this.skipTrivia();
13400
+ this.skipMacroDefinitionTrivia();
13296
13401
  const arg_tokens = [];
13297
- while (!this.check("STATEMENT_TERMINATOR") && !this.isAtEnd() && !this.isTrivia()) {
13402
+ while (!this.check("STATEMENT_TERMINATOR") && !this.isAtEnd()) {
13403
+ if (this.skipContinuation()) {
13404
+ continue;
13405
+ }
13406
+ if (this.check("COMMENT_LINE") || this.check("COMMENT_BLOCK")) {
13407
+ break;
13408
+ }
13298
13409
  const token = this.advance();
13299
13410
  arg_tokens.push(token);
13300
13411
  }
@@ -13399,7 +13510,7 @@ var init_parser = __esm(() => {
13399
13510
  range: prefix_token.range
13400
13511
  };
13401
13512
  if (prefix_token.value === "by") {
13402
- if (this.check("COLON")) {}
13513
+ if (this.check("COLON")) {} else {}
13403
13514
  }
13404
13515
  if (this.check("COLON")) {
13405
13516
  this.advance();
@@ -14158,7 +14269,7 @@ var init_parser = __esm(() => {
14158
14269
  } else if (token.type === "RPAREN") {
14159
14270
  paren_depth--;
14160
14271
  if (paren_depth < 0) {
14161
- this.addError("Unbalanced parentheses in if condition", token.range, 3011 /* UNBALANCED_PARENTHESES */);
14272
+ this.addError("Unbalanced parentheses in if condition", token.range, "UNBALANCED_PARENTHESES" /* UNBALANCED_PARENTHESES */);
14162
14273
  paren_depth = 0;
14163
14274
  }
14164
14275
  }
@@ -14168,10 +14279,10 @@ var init_parser = __esm(() => {
14168
14279
  }
14169
14280
  const condition = this.reconstructTokensWithSpacing(condition_tokens).trim();
14170
14281
  if (paren_depth > 0) {
14171
- this.addError("Unbalanced parentheses in if condition: missing closing parenthesis", ifToken.range, 3011 /* UNBALANCED_PARENTHESES */);
14282
+ this.addError("Unbalanced parentheses in if condition: missing closing parenthesis", ifToken.range, "UNBALANCED_PARENTHESES" /* UNBALANCED_PARENTHESES */);
14172
14283
  }
14173
14284
  if (condition.trim() === "") {
14174
- this.addError("Empty if condition", ifToken.range, 3010 /* MISSING_EXPRESSION_AFTER_EQUALS */);
14285
+ this.addError("Empty if condition", ifToken.range, "MISSING_EXPRESSION_AFTER_EQUALS" /* MISSING_EXPRESSION_AFTER_EQUALS */);
14175
14286
  }
14176
14287
  const body = [];
14177
14288
  if (this.check("LBRACE")) {
@@ -14323,7 +14434,7 @@ var init_parser = __esm(() => {
14323
14434
  } else if (token.type === "RPAREN") {
14324
14435
  paren_depth--;
14325
14436
  if (paren_depth < 0) {
14326
- this.addError("Unbalanced parentheses in while condition", token.range, 3011 /* UNBALANCED_PARENTHESES */);
14437
+ this.addError("Unbalanced parentheses in while condition", token.range, "UNBALANCED_PARENTHESES" /* UNBALANCED_PARENTHESES */);
14327
14438
  paren_depth = 0;
14328
14439
  }
14329
14440
  }
@@ -14333,10 +14444,10 @@ var init_parser = __esm(() => {
14333
14444
  }
14334
14445
  const condition = this.reconstructTokensWithSpacing(condition_tokens).trim();
14335
14446
  if (paren_depth > 0) {
14336
- this.addError("Unbalanced parentheses in while condition: missing closing parenthesis", whileToken.range, 3011 /* UNBALANCED_PARENTHESES */);
14447
+ this.addError("Unbalanced parentheses in while condition: missing closing parenthesis", whileToken.range, "UNBALANCED_PARENTHESES" /* UNBALANCED_PARENTHESES */);
14337
14448
  }
14338
14449
  if (condition.trim() === "") {
14339
- this.addError("Empty while condition", whileToken.range, 3010 /* MISSING_EXPRESSION_AFTER_EQUALS */);
14450
+ this.addError("Empty while condition", whileToken.range, "MISSING_EXPRESSION_AFTER_EQUALS" /* MISSING_EXPRESSION_AFTER_EQUALS */);
14340
14451
  }
14341
14452
  const body = [];
14342
14453
  if (this.check("LBRACE")) {
@@ -14553,30 +14664,52 @@ var init_parser = __esm(() => {
14553
14664
  this.advance();
14554
14665
  }
14555
14666
  }
14556
- looksLikeMacroDefinition() {
14557
- let offset = 1;
14667
+ skipMacroDefinitionTrivia() {
14668
+ while (!this.isAtEnd()) {
14669
+ if (this.skipContinuation()) {
14670
+ continue;
14671
+ }
14672
+ if (this.check("WHITESPACE") || this.check("COMMENT_LINE") || this.check("COMMENT_BLOCK")) {
14673
+ this.advance();
14674
+ continue;
14675
+ }
14676
+ break;
14677
+ }
14678
+ }
14679
+ nextSignificantOffsetForMacroDef(offset) {
14558
14680
  while (this.current + offset < this.tokens.length) {
14559
14681
  const token = this.tokens[this.current + offset];
14560
- if (token.type === "COMMENT_LINE" || token.type === "COMMENT_BLOCK" || token.type === "CONTINUATION" || token.type === "WHITESPACE") {
14682
+ if (token.type === "CONTINUATION") {
14561
14683
  offset++;
14684
+ if (this.current + offset < this.tokens.length && this.tokens[this.current + offset].type === "STATEMENT_TERMINATOR") {
14685
+ offset++;
14686
+ }
14562
14687
  continue;
14563
14688
  }
14564
- if (token.type === "WORD") {
14565
- return true;
14566
- }
14567
- if (token.type === "OPERATOR" && (token.value === "++" || token.value === "--")) {
14689
+ if (token.type === "COMMENT_LINE" || token.type === "COMMENT_BLOCK" || token.type === "WHITESPACE") {
14568
14690
  offset++;
14569
- while (this.current + offset < this.tokens.length) {
14570
- const next_token = this.tokens[this.current + offset];
14571
- if (next_token.type === "COMMENT_LINE" || next_token.type === "COMMENT_BLOCK" || next_token.type === "CONTINUATION" || next_token.type === "WHITESPACE") {
14572
- offset++;
14573
- continue;
14574
- }
14575
- return next_token.type === "WORD";
14576
- }
14691
+ continue;
14577
14692
  }
14693
+ break;
14694
+ }
14695
+ return offset;
14696
+ }
14697
+ looksLikeMacroDefinition() {
14698
+ let offset = this.nextSignificantOffsetForMacroDef(1);
14699
+ if (this.current + offset >= this.tokens.length) {
14578
14700
  return false;
14579
14701
  }
14702
+ const token = this.tokens[this.current + offset];
14703
+ if (token.type === "WORD") {
14704
+ return true;
14705
+ }
14706
+ if (token.type === "OPERATOR" && (token.value === "++" || token.value === "--")) {
14707
+ offset = this.nextSignificantOffsetForMacroDef(offset + 1);
14708
+ if (this.current + offset >= this.tokens.length) {
14709
+ return false;
14710
+ }
14711
+ return this.tokens[this.current + offset].type === "WORD";
14712
+ }
14580
14713
  return false;
14581
14714
  }
14582
14715
  skipToStatementEnd() {
@@ -14643,7 +14776,7 @@ var init_parser = __esm(() => {
14643
14776
  previous() {
14644
14777
  return this.tokens[this.current - 1];
14645
14778
  }
14646
- addError(message, range, code = 3000 /* SYNTAX_ERROR */) {
14779
+ addError(message, range, code = "SYNTAX_ERROR" /* SYNTAX_ERROR */) {
14647
14780
  this.errors.push({
14648
14781
  message,
14649
14782
  range,
@@ -14670,7 +14803,7 @@ var init_parser = __esm(() => {
14670
14803
  } else if (token.type === "RPAREN") {
14671
14804
  paren_depth--;
14672
14805
  if (paren_depth < 0) {
14673
- this.addError("Unbalanced parentheses: unexpected closing parenthesis", token.range, 3011 /* UNBALANCED_PARENTHESES */);
14806
+ this.addError("Unbalanced parentheses: unexpected closing parenthesis", token.range, "UNBALANCED_PARENTHESES" /* UNBALANCED_PARENTHESES */);
14674
14807
  paren_depth = 0;
14675
14808
  }
14676
14809
  }
@@ -14694,12 +14827,12 @@ var init_parser = __esm(() => {
14694
14827
  }
14695
14828
  if (paren_depth > 0) {
14696
14829
  const end_pos = this.current > 0 ? this.previous().range : this.peek().range;
14697
- this.addError("Unbalanced parentheses: missing closing parenthesis", end_pos, 3011 /* UNBALANCED_PARENTHESES */);
14830
+ this.addError("Unbalanced parentheses: missing closing parenthesis", end_pos, "UNBALANCED_PARENTHESES" /* UNBALANCED_PARENTHESES */);
14698
14831
  }
14699
14832
  const trimmed_expression = expression.trim();
14700
14833
  if (trimmed_expression === "") {
14701
14834
  const equals_pos = start_pos > 0 ? this.tokens[start_pos - 1].range : this.peek().range;
14702
- this.addError("Missing expression after equals sign", equals_pos, 3010 /* MISSING_EXPRESSION_AFTER_EQUALS */);
14835
+ this.addError("Missing expression after equals sign", equals_pos, "MISSING_EXPRESSION_AFTER_EQUALS" /* MISSING_EXPRESSION_AFTER_EQUALS */);
14703
14836
  }
14704
14837
  return trimmed_expression;
14705
14838
  }
@@ -14738,7 +14871,7 @@ var init_parser = __esm(() => {
14738
14871
  } else if (token.type === "RPAREN") {
14739
14872
  paren_depth--;
14740
14873
  if (paren_depth < 0) {
14741
- this.addError(`Unbalanced parentheses in ${qualifier_type} qualifier`, token.range, 3011 /* UNBALANCED_PARENTHESES */);
14874
+ this.addError(`Unbalanced parentheses in ${qualifier_type} qualifier`, token.range, "UNBALANCED_PARENTHESES" /* UNBALANCED_PARENTHESES */);
14742
14875
  paren_depth = 0;
14743
14876
  }
14744
14877
  if (state_stack.length > 1) {
@@ -14785,7 +14918,7 @@ var init_parser = __esm(() => {
14785
14918
  const current_state = state_stack[state_stack.length - 1];
14786
14919
  if (current_state === "AFTER_RHS" && token.type !== "LPAREN" && token.type !== "RPAREN" && token.type !== "LBRACKET" && token.type !== "RBRACKET" && bracket_depth === 0 && !in_string_context && !is_delimiter_only) {
14787
14920
  if (prev_token && this.detectSplitLiteral(prev_token, token)) {} else if (!this.isValidAfterComparison(token)) {
14788
- this.addError(`Unexpected token '${token.value}' after comparison expression. Did you mean to use '&' or '|'?`, token.range, 3013 /* STRAY_TOKEN_IN_CONDITION */);
14921
+ this.addError(`Unexpected token '${token.value}' after comparison expression. Did you mean to use '&' or '|'?`, token.range, "STRAY_TOKEN_IN_CONDITION" /* STRAY_TOKEN_IN_CONDITION */);
14789
14922
  }
14790
14923
  }
14791
14924
  if (token.type !== "WHITESPACE" && token.type !== "LPAREN" && token.type !== "RPAREN" && bracket_depth === 0) {
@@ -14824,11 +14957,11 @@ var init_parser = __esm(() => {
14824
14957
  }
14825
14958
  }
14826
14959
  if (paren_depth > 0) {
14827
- this.addError(`Unbalanced parentheses in ${qualifier_type} qualifier: missing closing parenthesis`, start_token.range, 3011 /* UNBALANCED_PARENTHESES */);
14960
+ this.addError(`Unbalanced parentheses in ${qualifier_type} qualifier: missing closing parenthesis`, start_token.range, "UNBALANCED_PARENTHESES" /* UNBALANCED_PARENTHESES */);
14828
14961
  }
14829
14962
  const trimmed_expression = expression.trim();
14830
14963
  if (check_empty && trimmed_expression === "") {
14831
- this.addError(`Empty ${qualifier_type} qualifier expression`, start_token.range, 3010 /* MISSING_EXPRESSION_AFTER_EQUALS */);
14964
+ this.addError(`Empty ${qualifier_type} qualifier expression`, start_token.range, "MISSING_EXPRESSION_AFTER_EQUALS" /* MISSING_EXPRESSION_AFTER_EQUALS */);
14832
14965
  }
14833
14966
  return trimmed_expression;
14834
14967
  }
@@ -14839,21 +14972,21 @@ var init_parser = __esm(() => {
14839
14972
  const is_prev_dot = prev_token.value === "." && (prev_token.type === "OPERATOR" || prev_token.type === "WORD");
14840
14973
  if (is_prev_dot) {
14841
14974
  if (current_token.type === "NUMBER") {
14842
- this.addError(`Split literal detected: '${prev_token.value} ${current_token.value}' may have been intended as '.${current_token.value}'`, { start: prev_token.range.start, end: current_token.range.end }, 3014 /* SPLIT_LITERAL_IN_CONDITION */);
14975
+ this.addError(`Split literal detected: '${prev_token.value} ${current_token.value}' may have been intended as '.${current_token.value}'`, { start: prev_token.range.start, end: current_token.range.end }, "SPLIT_LITERAL_IN_CONDITION" /* SPLIT_LITERAL_IN_CONDITION */);
14843
14976
  return true;
14844
14977
  }
14845
14978
  if (current_token.type === "WORD" && /^[a-z]$/i.test(current_token.value)) {
14846
- this.addError(`Split literal detected: '${prev_token.value} ${current_token.value}' may have been intended as '.${current_token.value}' (extended missing value)`, { start: prev_token.range.start, end: current_token.range.end }, 3014 /* SPLIT_LITERAL_IN_CONDITION */);
14979
+ this.addError(`Split literal detected: '${prev_token.value} ${current_token.value}' may have been intended as '.${current_token.value}' (extended missing value)`, { start: prev_token.range.start, end: current_token.range.end }, "SPLIT_LITERAL_IN_CONDITION" /* SPLIT_LITERAL_IN_CONDITION */);
14847
14980
  return true;
14848
14981
  }
14849
14982
  }
14850
14983
  const is_current_dot = current_token.value === "." && (current_token.type === "OPERATOR" || current_token.type === "WORD");
14851
14984
  if (prev_token.type === "NUMBER" && is_current_dot) {
14852
- this.addError(`Split literal detected: '${prev_token.value} ${current_token.value}' may have been intended as '${prev_token.value}.' or the '.' may be stray`, { start: prev_token.range.start, end: current_token.range.end }, 3014 /* SPLIT_LITERAL_IN_CONDITION */);
14985
+ this.addError(`Split literal detected: '${prev_token.value} ${current_token.value}' may have been intended as '${prev_token.value}.' or the '.' may be stray`, { start: prev_token.range.start, end: current_token.range.end }, "SPLIT_LITERAL_IN_CONDITION" /* SPLIT_LITERAL_IN_CONDITION */);
14853
14986
  return true;
14854
14987
  }
14855
14988
  if (prev_token.type === "WORD" && prev_token.value !== "." && is_current_dot) {
14856
- this.addError(`Split literal detected: '${prev_token.value} ${current_token.value}' - the '.' may be stray or part of a split literal`, { start: prev_token.range.start, end: current_token.range.end }, 3014 /* SPLIT_LITERAL_IN_CONDITION */);
14989
+ this.addError(`Split literal detected: '${prev_token.value} ${current_token.value}' - the '.' may be stray or part of a split literal`, { start: prev_token.range.start, end: current_token.range.end }, "SPLIT_LITERAL_IN_CONDITION" /* SPLIT_LITERAL_IN_CONDITION */);
14857
14990
  return true;
14858
14991
  }
14859
14992
  return false;
@@ -14930,7 +15063,7 @@ var init_parser = __esm(() => {
14930
15063
  this.errors.push({
14931
15064
  message: "close brace must be alone on its line",
14932
15065
  range: this.makeRange(code_before.range.start, brace_token.range.end),
14933
- code: 3002 /* BRACE_NOT_ALONE */
15066
+ code: "BRACE_NOT_ALONE" /* BRACE_NOT_ALONE */
14934
15067
  });
14935
15068
  }
14936
15069
  const code_after = this.find_code_after_on_same_line(brace_index + 1, brace_line);
@@ -14939,13 +15072,13 @@ var init_parser = __esm(() => {
14939
15072
  this.errors.push({
14940
15073
  message: "else must appear on a separate line from close brace",
14941
15074
  range: this.makeRange(brace_token.range.start, code_after.range.end),
14942
- code: 3001 /* BRACE_ELSE_SAME_LINE */
15075
+ code: "BRACE_ELSE_SAME_LINE" /* BRACE_ELSE_SAME_LINE */
14943
15076
  });
14944
15077
  } else {
14945
15078
  this.errors.push({
14946
15079
  message: "code follows on the same line as close brace",
14947
15080
  range: this.makeRange(brace_token.range.start, code_after.range.end),
14948
- code: 3002 /* BRACE_NOT_ALONE */
15081
+ code: "BRACE_NOT_ALONE" /* BRACE_NOT_ALONE */
14949
15082
  });
14950
15083
  }
14951
15084
  }
@@ -14958,7 +15091,7 @@ var init_parser = __esm(() => {
14958
15091
  this.errors.push({
14959
15092
  message: "open brace must be on the same line as the condition",
14960
15093
  range: brace_token.range,
14961
- code: 3004 /* OPEN_BRACE_ALONE */
15094
+ code: "OPEN_BRACE_ALONE" /* OPEN_BRACE_ALONE */
14962
15095
  });
14963
15096
  }
14964
15097
  }
@@ -14986,7 +15119,7 @@ var init_parser = __esm(() => {
14986
15119
  this.errors.push({
14987
15120
  message: "code after open brace may be silently ignored",
14988
15121
  range: this.makeRange(brace_token.range.start, last_token.range.end),
14989
- code: 3006 /* CODE_AFTER_OPEN_BRACE */
15122
+ code: "CODE_AFTER_OPEN_BRACE" /* CODE_AFTER_OPEN_BRACE */
14990
15123
  });
14991
15124
  }
14992
15125
  }
@@ -15094,6 +15227,71 @@ var init_stata_call_patterns = __esm(() => {
15094
15227
  CALL_PREFIX_ALTERNATIVES = /qui(?:etly)?|cap(?:ture)?|noi(?:sily)?|version\s+\d+(?:\.\d+)?/.source;
15095
15228
  });
15096
15229
 
15230
+ // src/utils/block-comment-utils.ts
15231
+ function block_comment_ranges(content, tokens) {
15232
+ const the_tokens = tokens ?? new StataLexer().tokenize(content).tokens;
15233
+ return the_tokens.filter((my_token) => my_token.type === "COMMENT_BLOCK" || my_token.type === "COMMENT_LINE" && my_token.range.end.line > my_token.range.start.line).map((my_token) => my_token.range);
15234
+ }
15235
+ function position_in_block_comment(line, character, ranges) {
15236
+ for (const my_range of ranges) {
15237
+ const after_start = line > my_range.start.line || line === my_range.start.line && character >= my_range.start.character;
15238
+ const before_end = line < my_range.end.line || line === my_range.end.line && character < my_range.end.character;
15239
+ if (after_start && before_end) {
15240
+ return true;
15241
+ }
15242
+ }
15243
+ return false;
15244
+ }
15245
+ function block_comment_lines(content, tokens) {
15246
+ const the_comment_ranges = block_comment_ranges(content, tokens);
15247
+ const the_lines = new Set;
15248
+ if (the_comment_ranges.length === 0) {
15249
+ return the_lines;
15250
+ }
15251
+ const doc = { content, line_offsets: compute_line_offsets(content) };
15252
+ const line_count = get_line_count(doc);
15253
+ for (let my_line = 0;my_line < line_count; my_line++) {
15254
+ const my_text = get_line_text(doc, my_line);
15255
+ const my_col = my_text.search(/\S/);
15256
+ if (my_col < 0) {
15257
+ continue;
15258
+ }
15259
+ if (position_in_block_comment(my_line, my_col, the_comment_ranges)) {
15260
+ the_lines.add(my_line);
15261
+ }
15262
+ }
15263
+ return the_lines;
15264
+ }
15265
+ var init_block_comment_utils = __esm(() => {
15266
+ init_lexer();
15267
+ });
15268
+
15269
+ // src/utils/directives.ts
15270
+ function make_directive_pattern(keywords, suffix, flags) {
15271
+ return new RegExp(`${DIRECTIVE_PREFIX_PATTERN}(${keywords})${suffix}`, flags);
15272
+ }
15273
+ function has_ignore_directive(text) {
15274
+ return IGNORE_DIRECTIVE_REGEX.test(text);
15275
+ }
15276
+ function has_trailing_ignore_directive(text) {
15277
+ return TRAILING_IGNORE_DIRECTIVE_REGEX.test(text);
15278
+ }
15279
+ function has_ignore_next_directive(text) {
15280
+ return IGNORE_NEXT_DIRECTIVE_REGEX.test(text);
15281
+ }
15282
+ var DIRECTIVE_BODY_PREFIX_PATTERN, DIRECTIVE_PREFIX_PATTERN, FORWARD_DIRECTIVE_KEYWORDS = "do|run|include", BACKWARD_DIRECTIVE_KEYWORDS = "done-by|run-by|included-by", CALL_SITE_PARAMS_FRAGMENT, WORKING_DIR_DIRECTIVE_KEYWORDS = "working-directory|working-dir|current-directory|current-dir|cd|wd", DECLARATION_DIRECTIVE_KEYWORDS = "local|global|scalar|matrix|program", DIRECTIVE_PREFIX_REGEX, IGNORE_DIRECTIVE_REGEX, IGNORE_NEXT_DIRECTIVE_REGEX, VARIABLES_DIRECTIVE_PATTERN, DECLARATION_DIRECTIVE_PATTERN, TRAILING_IGNORE_DIRECTIVE_REGEX;
15283
+ var init_directives = __esm(() => {
15284
+ DIRECTIVE_BODY_PREFIX_PATTERN = String.raw`(?:@lsp-|sight:\s*)`;
15285
+ DIRECTIVE_PREFIX_PATTERN = String.raw`^\s*(?://|\*)\s*${DIRECTIVE_BODY_PREFIX_PATTERN}`;
15286
+ CALL_SITE_PARAMS_FRAGMENT = String.raw`(?:\s+(?:line=\d+|match="(?:\\"|[^"])+"))*`;
15287
+ DIRECTIVE_PREFIX_REGEX = new RegExp(DIRECTIVE_PREFIX_PATTERN);
15288
+ IGNORE_DIRECTIVE_REGEX = new RegExp(`${DIRECTIVE_PREFIX_PATTERN}ignore:?\\s*$`);
15289
+ IGNORE_NEXT_DIRECTIVE_REGEX = new RegExp(`${DIRECTIVE_PREFIX_PATTERN}ignore-next:?\\s*$`);
15290
+ VARIABLES_DIRECTIVE_PATTERN = new RegExp(`${DIRECTIVE_PREFIX_PATTERN}variables:?\\s+(.+)\\s*$`);
15291
+ DECLARATION_DIRECTIVE_PATTERN = new RegExp(`${DIRECTIVE_PREFIX_PATTERN}(${DECLARATION_DIRECTIVE_KEYWORDS}):?\\s+(.+)\\s*$`);
15292
+ TRAILING_IGNORE_DIRECTIVE_REGEX = new RegExp(`//\\s*${DIRECTIVE_BODY_PREFIX_PATTERN}ignore:?\\s*$`);
15293
+ });
15294
+
15097
15295
  // src/directive-parser/index.ts
15098
15296
  import * as path2 from "path";
15099
15297
  import * as fs3 from "fs";
@@ -15106,7 +15304,7 @@ function looks_like_unquoted_path_token(token) {
15106
15304
  }
15107
15305
 
15108
15306
  class DirectiveParser {
15109
- parse(content, file_uri) {
15307
+ parse(content, file_uri, tokens) {
15110
15308
  const doc = { content, line_offsets: compute_line_offsets(content) };
15111
15309
  const line_count = get_line_count(doc);
15112
15310
  const the_directives = [];
@@ -15114,7 +15312,11 @@ class DirectiveParser {
15114
15312
  const containing_dir = path2.dirname(URI.parse(file_uri).fsPath);
15115
15313
  let working_directory;
15116
15314
  let working_dir_count = 0;
15315
+ const block_lines = block_comment_lines(content, tokens);
15117
15316
  for (let i = 0;i < line_count; i++) {
15317
+ if (block_lines.has(i)) {
15318
+ continue;
15319
+ }
15118
15320
  const my_line = get_line_text(doc, i);
15119
15321
  const my_trimmed = my_line.trim();
15120
15322
  if (my_trimmed !== "" && !my_trimmed.startsWith("*") && !my_trimmed.startsWith("//")) {
@@ -15157,10 +15359,10 @@ class DirectiveParser {
15157
15359
  const my_quoted_path = my_match[2];
15158
15360
  const my_unquoted_path = my_match[3];
15159
15361
  const my_raw_path = my_quoted_path || my_unquoted_path;
15160
- const my_params = my_trimmed.slice((my_match.index ?? 0) + my_match[0].length).trim();
15362
+ const my_params = my_match[4]?.trim() ?? "";
15161
15363
  if (!my_quoted_path && my_unquoted_path && !looks_like_unquoted_path_token(my_unquoted_path)) {
15162
15364
  the_diagnostics.push({
15163
- message: "Malformed directive. Expected: " + '// @lsp-done-by: "path.do" or // @lsp-run-by: "path.do" or // @lsp-included-by: "path.do"',
15365
+ message: "Malformed directive. Expected: " + '// sight: done-by: "path.do" or // sight: run-by: "path.do" or // sight: included-by: "path.do"',
15164
15366
  range: {
15165
15367
  start: { line: i, character: 0 },
15166
15368
  end: { line: i, character: my_line.length }
@@ -15182,9 +15384,9 @@ class DirectiveParser {
15182
15384
  call_site: my_call_site,
15183
15385
  range: my_range
15184
15386
  });
15185
- } else if (my_trimmed.includes("@lsp-done-by") || my_trimmed.includes("@lsp-run-by") || my_trimmed.includes("@lsp-included-by")) {
15387
+ } else if (BACKWARD_DIRECTIVE_HEAD_PATTERN.test(my_trimmed)) {
15186
15388
  the_diagnostics.push({
15187
- message: "Malformed directive. Expected: " + '// @lsp-done-by "path" or // @lsp-run-by "path" or // @lsp-included-by "path"',
15389
+ message: "Malformed directive. Expected: " + '// sight: done-by "path" or // sight: run-by "path" or // sight: included-by "path"',
15188
15390
  range: {
15189
15391
  start: { line: i, character: 0 },
15190
15392
  end: { line: i, character: my_line.length }
@@ -15193,9 +15395,9 @@ class DirectiveParser {
15193
15395
  });
15194
15396
  }
15195
15397
  }
15196
- const declaration_result = this.parse_declaration_directives(content, file_uri);
15398
+ const declaration_result = this.parse_declaration_directives(content, file_uri, tokens);
15197
15399
  the_diagnostics.push(...declaration_result.diagnostics);
15198
- const forward_call_result = this.parse_forward_call_directives(content, file_uri);
15400
+ const forward_call_result = this.parse_forward_call_directives(content, file_uri, tokens);
15199
15401
  the_diagnostics.push(...forward_call_result.diagnostics);
15200
15402
  if (working_dir_count > 1 && working_directory) {
15201
15403
  the_diagnostics.push({
@@ -15212,17 +15414,25 @@ class DirectiveParser {
15212
15414
  diagnostics: the_diagnostics
15213
15415
  };
15214
15416
  }
15215
- parse_forward_call_directives(content, _file_uri) {
15417
+ parse_forward_call_directives(content, _file_uri, tokens) {
15216
15418
  const doc = { content, line_offsets: compute_line_offsets(content) };
15217
15419
  const line_count = get_line_count(doc);
15218
15420
  const the_forward_calls = [];
15219
15421
  const the_diagnostics = [];
15422
+ const block_lines = block_comment_lines(content, tokens);
15423
+ let the_block_ranges;
15220
15424
  const ignored_next_lines = new Set;
15221
15425
  for (let i = 0;i < line_count; i++) {
15426
+ if (block_lines.has(i)) {
15427
+ continue;
15428
+ }
15222
15429
  const my_line = get_line_text(doc, i);
15223
15430
  const my_trimmed = my_line.trim();
15224
- if ((my_trimmed.startsWith("*") || my_trimmed.startsWith("//")) && my_trimmed.includes("@lsp-ignore-next")) {
15431
+ if ((my_trimmed.startsWith("*") || my_trimmed.startsWith("//")) && (has_ignore_directive(my_trimmed) || has_ignore_next_directive(my_trimmed))) {
15225
15432
  for (let j = i + 1;j < line_count; j++) {
15433
+ if (block_lines.has(j)) {
15434
+ continue;
15435
+ }
15226
15436
  const next_trimmed = get_line_text(doc, j).trim();
15227
15437
  if (next_trimmed !== "" && !next_trimmed.startsWith("*") && !next_trimmed.startsWith("//")) {
15228
15438
  ignored_next_lines.add(j);
@@ -15236,6 +15446,9 @@ class DirectiveParser {
15236
15446
  }
15237
15447
  }
15238
15448
  for (let i = 0;i < line_count; i++) {
15449
+ if (block_lines.has(i)) {
15450
+ continue;
15451
+ }
15239
15452
  const my_line = get_line_text(doc, i);
15240
15453
  const my_trimmed = my_line.trim();
15241
15454
  if (!my_trimmed.startsWith("*") && !my_trimmed.startsWith("//")) {
@@ -15243,9 +15456,6 @@ class DirectiveParser {
15243
15456
  }
15244
15457
  const my_match = my_trimmed.match(FORWARD_CALL_DIRECTIVE_PATTERN);
15245
15458
  if (my_match) {
15246
- if (my_trimmed.includes("@lsp-ignore") && !my_trimmed.includes("@lsp-ignore-next")) {
15247
- continue;
15248
- }
15249
15459
  if (ignored_next_lines.has(i)) {
15250
15460
  continue;
15251
15461
  }
@@ -15253,7 +15463,7 @@ class DirectiveParser {
15253
15463
  const my_quoted_path = my_match[2];
15254
15464
  const my_unquoted_path = my_match[3];
15255
15465
  const my_raw_path = my_quoted_path || my_unquoted_path;
15256
- const my_params = my_trimmed.slice((my_match.index ?? 0) + my_match[0].length).trim();
15466
+ const my_params = my_match[4]?.trim() ?? "";
15257
15467
  if (!my_raw_path) {
15258
15468
  the_diagnostics.push({
15259
15469
  message: "Forward call directive requires a path",
@@ -15264,7 +15474,7 @@ class DirectiveParser {
15264
15474
  }
15265
15475
  if (!my_quoted_path && my_unquoted_path && !looks_like_unquoted_path_token(my_unquoted_path)) {
15266
15476
  the_diagnostics.push({
15267
- message: "Malformed directive. Expected: " + '// @lsp-do: "path.do" or // @lsp-run: "path.do" or // @lsp-include: "path.do"',
15477
+ message: "Malformed directive. Expected: " + '// sight: do: "path.do" or // sight: run: "path.do" or // sight: include: "path.do"',
15268
15478
  range: { start: { line: i, character: 0 }, end: { line: i, character: my_line.length } },
15269
15479
  severity: "warning"
15270
15480
  });
@@ -15279,7 +15489,10 @@ class DirectiveParser {
15279
15489
  if (my_call_site?.type === "line" && typeof my_call_site.value === "number") {
15280
15490
  my_call_site_line = Math.max(0, my_call_site.value - 1);
15281
15491
  } else if (my_call_site?.type === "match" && typeof my_call_site.value === "string") {
15282
- const match_line = this.find_match_line(content, my_call_site.value);
15492
+ if (the_block_ranges === undefined) {
15493
+ the_block_ranges = block_comment_ranges(content, tokens);
15494
+ }
15495
+ const match_line = this.find_match_line(content, my_call_site.value, the_block_ranges);
15283
15496
  if (match_line !== undefined) {
15284
15497
  my_call_site_line = match_line;
15285
15498
  } else {
@@ -15303,22 +15516,32 @@ class DirectiveParser {
15303
15516
  call_site: my_call_site,
15304
15517
  range: my_range
15305
15518
  });
15519
+ } else if (!ignored_next_lines.has(i) && FORWARD_CALL_DIRECTIVE_HEAD_PATTERN.test(my_trimmed)) {
15520
+ the_diagnostics.push({
15521
+ message: "Malformed directive. Expected: " + '// sight: do: "path.do" or // sight: run: "path.do" or // sight: include: "path.do"',
15522
+ range: { start: { line: i, character: 0 }, end: { line: i, character: my_line.length } },
15523
+ severity: "warning"
15524
+ });
15306
15525
  }
15307
15526
  }
15308
15527
  return { forward_calls: the_forward_calls, diagnostics: the_diagnostics };
15309
15528
  }
15310
- parse_declaration_directives(content, _file_uri) {
15529
+ parse_declaration_directives(content, _file_uri, tokens) {
15311
15530
  const doc = { content, line_offsets: compute_line_offsets(content) };
15312
15531
  const line_count = get_line_count(doc);
15313
15532
  const the_declarations = [];
15314
15533
  const the_diagnostics = [];
15534
+ const block_lines = block_comment_lines(content, tokens);
15315
15535
  for (let i = 0;i < line_count; i++) {
15536
+ if (block_lines.has(i)) {
15537
+ continue;
15538
+ }
15316
15539
  const my_line = get_line_text(doc, i);
15317
15540
  const my_trimmed = my_line.trim();
15318
15541
  if (!my_trimmed.startsWith("*") && !my_trimmed.startsWith("//")) {
15319
15542
  continue;
15320
15543
  }
15321
- const my_match = my_trimmed.match(DECLARATION_DIRECTIVE_PATTERN);
15544
+ const my_match = my_trimmed.match(DECLARATION_DIRECTIVE_HEAD_PATTERN);
15322
15545
  if (my_match) {
15323
15546
  const my_type = my_match[1];
15324
15547
  const my_rest = my_trimmed.slice((my_match.index ?? 0) + my_match[0].length).trim();
@@ -15349,7 +15572,8 @@ class DirectiveParser {
15349
15572
  parse_call_site(params) {
15350
15573
  const my_match_result = params.match(PARAM_MATCH);
15351
15574
  if (my_match_result) {
15352
- return { type: "match", value: my_match_result[1] };
15575
+ const my_value = my_match_result[1].replace(/\\"/g, '"');
15576
+ return { type: "match", value: my_value };
15353
15577
  }
15354
15578
  const my_line_result = params.match(PARAM_LINE);
15355
15579
  if (my_line_result) {
@@ -15380,12 +15604,44 @@ class DirectiveParser {
15380
15604
  }
15381
15605
  return my_resolved;
15382
15606
  }
15383
- find_match_line(parent_content, match_string) {
15607
+ find_match_line(parent_content, match_string, block_ranges) {
15384
15608
  const doc = { content: parent_content, line_offsets: compute_line_offsets(parent_content) };
15385
15609
  const line_count = get_line_count(doc);
15610
+ const the_block_ranges = block_ranges ?? block_comment_ranges(parent_content);
15386
15611
  for (let i = 0;i < line_count; i++) {
15387
- if (get_line_text(doc, i).includes(match_string)) {
15388
- return i;
15612
+ const my_text = get_line_text(doc, i);
15613
+ let my_from = 0;
15614
+ while (my_from <= my_text.length) {
15615
+ const my_col = my_text.indexOf(match_string, my_from);
15616
+ if (my_col < 0) {
15617
+ break;
15618
+ }
15619
+ if (!position_in_block_comment(i, my_col, the_block_ranges)) {
15620
+ return i;
15621
+ }
15622
+ my_from = my_col + 1;
15623
+ }
15624
+ }
15625
+ return;
15626
+ }
15627
+ classify_call_line(line_content) {
15628
+ const my_trimmed = line_content.trim();
15629
+ const command_match = my_trimmed.match(DO_INCLUDE_PATTERN);
15630
+ if (command_match) {
15631
+ const my_path = command_match[2] || command_match[3];
15632
+ if (my_path) {
15633
+ return command_match[1];
15634
+ }
15635
+ }
15636
+ if (my_trimmed.startsWith("*") || my_trimmed.startsWith("//")) {
15637
+ const directive_match = my_trimmed.match(FORWARD_CALL_DIRECTIVE_PATTERN);
15638
+ if (directive_match) {
15639
+ const my_quoted_path = directive_match[2];
15640
+ const my_unquoted_path = directive_match[3];
15641
+ const my_path = my_quoted_path || my_unquoted_path;
15642
+ if (my_path && (my_quoted_path || looks_like_unquoted_path_token(my_unquoted_path))) {
15643
+ return directive_match[1];
15644
+ }
15389
15645
  }
15390
15646
  }
15391
15647
  return;
@@ -15395,7 +15651,11 @@ class DirectiveParser {
15395
15651
  const line_count = get_line_count(doc);
15396
15652
  const child_basename = path2.basename(child_filename);
15397
15653
  const child_without_ext = child_basename.toLowerCase().endsWith(".do") ? child_basename.slice(0, -3).toLowerCase() : child_basename.toLowerCase();
15654
+ const block_lines = block_comment_lines(parent_content);
15398
15655
  for (let i = 0;i < line_count; i++) {
15656
+ if (block_lines.has(i)) {
15657
+ continue;
15658
+ }
15399
15659
  const my_line = get_line_text(doc, i);
15400
15660
  const my_trimmed = my_line.trim();
15401
15661
  const my_match = my_line.match(DO_INCLUDE_PATTERN);
@@ -15412,12 +15672,12 @@ class DirectiveParser {
15412
15672
  }
15413
15673
  }
15414
15674
  if (my_trimmed.startsWith("*") || my_trimmed.startsWith("//")) {
15415
- const directive_match = my_trimmed.match(CALL_DIRECTIVE_PATTERN);
15675
+ const directive_match = my_trimmed.match(FORWARD_CALL_DIRECTIVE_PATTERN);
15416
15676
  if (directive_match) {
15417
15677
  const my_quoted_path = directive_match[2];
15418
15678
  const my_unquoted_path = directive_match[3];
15419
15679
  const my_target_path = my_quoted_path || my_unquoted_path;
15420
- if (my_target_path) {
15680
+ if (my_target_path && (my_quoted_path || looks_like_unquoted_path_token(my_unquoted_path))) {
15421
15681
  const my_target_basename = path2.basename(my_target_path);
15422
15682
  const my_target_without_ext = my_target_basename.toLowerCase().endsWith(".do") ? my_target_basename.slice(0, -3).toLowerCase() : my_target_basename.toLowerCase();
15423
15683
  if (my_target_without_ext === child_without_ext) {
@@ -15434,7 +15694,11 @@ class DirectiveParser {
15434
15694
  const line_count = get_line_count(doc);
15435
15695
  const child_basename = path2.basename(child_filename);
15436
15696
  const child_without_ext = child_basename.toLowerCase().endsWith(".do") ? child_basename.slice(0, -3).toLowerCase() : child_basename.toLowerCase();
15697
+ const block_lines = block_comment_lines(parent_content);
15437
15698
  for (let i = 0;i < line_count; i++) {
15699
+ if (block_lines.has(i)) {
15700
+ continue;
15701
+ }
15438
15702
  const my_line = get_line_text(doc, i);
15439
15703
  const my_trimmed = my_line.trim();
15440
15704
  const my_match = my_line.match(DO_INCLUDE_PATTERN);
@@ -15452,13 +15716,13 @@ class DirectiveParser {
15452
15716
  }
15453
15717
  }
15454
15718
  if (my_trimmed.startsWith("*") || my_trimmed.startsWith("//")) {
15455
- const directive_match = my_trimmed.match(CALL_DIRECTIVE_PATTERN);
15719
+ const directive_match = my_trimmed.match(FORWARD_CALL_DIRECTIVE_PATTERN);
15456
15720
  if (directive_match) {
15457
15721
  const my_call_type = directive_match[1];
15458
15722
  const my_quoted_path = directive_match[2];
15459
15723
  const my_unquoted_path = directive_match[3];
15460
15724
  const my_target_path = my_quoted_path || my_unquoted_path;
15461
- if (my_target_path) {
15725
+ if (my_target_path && (my_quoted_path || looks_like_unquoted_path_token(my_unquoted_path))) {
15462
15726
  const my_target_basename = path2.basename(my_target_path);
15463
15727
  const my_target_without_ext = my_target_basename.toLowerCase().endsWith(".do") ? my_target_basename.slice(0, -3).toLowerCase() : my_target_basename.toLowerCase();
15464
15728
  if (my_target_without_ext === child_without_ext) {
@@ -15476,7 +15740,11 @@ class DirectiveParser {
15476
15740
  const the_call_sites = [];
15477
15741
  const child_basename = path2.basename(child_filename);
15478
15742
  const child_without_ext = child_basename.toLowerCase().endsWith(".do") ? child_basename.slice(0, -3).toLowerCase() : child_basename.toLowerCase();
15743
+ const block_lines = block_comment_lines(parent_content);
15479
15744
  for (let i = 0;i < line_count; i++) {
15745
+ if (block_lines.has(i)) {
15746
+ continue;
15747
+ }
15480
15748
  const my_line = get_line_text(doc, i);
15481
15749
  const my_trimmed = my_line.trim();
15482
15750
  const my_match = my_line.match(DO_INCLUDE_PATTERN);
@@ -15494,13 +15762,13 @@ class DirectiveParser {
15494
15762
  }
15495
15763
  }
15496
15764
  if (my_trimmed.startsWith("*") || my_trimmed.startsWith("//")) {
15497
- const directive_match = my_trimmed.match(CALL_DIRECTIVE_PATTERN);
15765
+ const directive_match = my_trimmed.match(FORWARD_CALL_DIRECTIVE_PATTERN);
15498
15766
  if (directive_match) {
15499
15767
  const my_call_type = directive_match[1];
15500
15768
  const my_quoted_path = directive_match[2];
15501
15769
  const my_unquoted_path = directive_match[3];
15502
15770
  const my_target_path = my_quoted_path || my_unquoted_path;
15503
- if (my_target_path) {
15771
+ if (my_target_path && (my_quoted_path || looks_like_unquoted_path_token(my_unquoted_path))) {
15504
15772
  const my_target_basename = path2.basename(my_target_path);
15505
15773
  const my_target_without_ext = my_target_basename.toLowerCase().endsWith(".do") ? my_target_basename.slice(0, -3).toLowerCase() : my_target_basename.toLowerCase();
15506
15774
  if (my_target_without_ext === child_without_ext) {
@@ -15513,18 +15781,22 @@ class DirectiveParser {
15513
15781
  return the_call_sites;
15514
15782
  }
15515
15783
  }
15516
- var DIRECTIVE_PATTERN, FORWARD_CALL_DIRECTIVE_PATTERN, WORKING_DIR_DIRECTIVE_PATTERN, PARAM_LINE, PARAM_MATCH, DECLARATION_DIRECTIVE_PATTERN, DO_INCLUDE_PATTERN, CALL_DIRECTIVE_PATTERN;
15784
+ var CALL_SITE_PARAMS_PATTERN, DIRECTIVE_PATTERN, BACKWARD_DIRECTIVE_HEAD_PATTERN, FORWARD_CALL_DIRECTIVE_PATTERN, FORWARD_CALL_DIRECTIVE_HEAD_PATTERN, WORKING_DIR_DIRECTIVE_PATTERN, PARAM_LINE, PARAM_MATCH, DECLARATION_DIRECTIVE_HEAD_PATTERN, DO_INCLUDE_PATTERN;
15517
15785
  var init_directive_parser = __esm(() => {
15518
15786
  init_esm();
15519
15787
  init_stata_call_patterns();
15520
- DIRECTIVE_PATTERN = /@lsp-(done-by|run-by|included-by):?\s+(?:"([^"]+)"|([^\s]+))/;
15521
- FORWARD_CALL_DIRECTIVE_PATTERN = /@lsp-(do|run|include):?\s+(?:"([^"]+)"|([^\s]+))/;
15522
- WORKING_DIR_DIRECTIVE_PATTERN = /@lsp-(working-directory|working-dir|current-directory|current-dir|cd|wd):?\s+(?:"([^"]+)"|([^\s]+))$/;
15788
+ init_block_comment_utils();
15789
+ init_directives();
15790
+ CALL_SITE_PARAMS_PATTERN = String.raw`(${CALL_SITE_PARAMS_FRAGMENT})\s*$`;
15791
+ DIRECTIVE_PATTERN = make_directive_pattern(BACKWARD_DIRECTIVE_KEYWORDS, String.raw`:?\s+(?:"([^"]+)"|([^\s]+))${CALL_SITE_PARAMS_PATTERN}`);
15792
+ BACKWARD_DIRECTIVE_HEAD_PATTERN = make_directive_pattern(BACKWARD_DIRECTIVE_KEYWORDS, String.raw`(?=:|\s|$)`);
15793
+ FORWARD_CALL_DIRECTIVE_PATTERN = make_directive_pattern(FORWARD_DIRECTIVE_KEYWORDS, String.raw`:?\s+(?:"([^"]+)"|([^\s]+))${CALL_SITE_PARAMS_PATTERN}`);
15794
+ FORWARD_CALL_DIRECTIVE_HEAD_PATTERN = make_directive_pattern(FORWARD_DIRECTIVE_KEYWORDS, String.raw`(?=:|\s|$)`);
15795
+ WORKING_DIR_DIRECTIVE_PATTERN = make_directive_pattern(WORKING_DIR_DIRECTIVE_KEYWORDS, String.raw`:?\s+(?:"([^"]+)"|([^\s]+))\s*$`);
15523
15796
  PARAM_LINE = /line=(\d+)/;
15524
- PARAM_MATCH = /match="([^"]+)"/;
15525
- DECLARATION_DIRECTIVE_PATTERN = /@lsp-(local|global|scalar|matrix|program)(?=\s|$)/;
15797
+ PARAM_MATCH = /match="((?:\\"|[^"])+)"/;
15798
+ DECLARATION_DIRECTIVE_HEAD_PATTERN = make_directive_pattern(DECLARATION_DIRECTIVE_KEYWORDS, String.raw`:?(?=\s|$)`);
15526
15799
  DO_INCLUDE_PATTERN = build_do_include_pattern("capture");
15527
- CALL_DIRECTIVE_PATTERN = /@lsp-(do|run|include):?\s+(?:"([^"]+)"|([^\s]+))/;
15528
15800
  });
15529
15801
 
15530
15802
  // src/analyzer/macro-creating-commands.ts
@@ -15675,20 +15947,23 @@ class SemanticAnalyzer {
15675
15947
  this.parse_declaration_directives_from_tokens(tokens, symbols);
15676
15948
  for (let i = 0;i < tokens.length; i++) {
15677
15949
  const token = tokens[i];
15678
- if (token.type === "COMMENT_LINE" || token.type === "COMMENT_BLOCK") {
15950
+ if (token.type === "COMMENT_LINE") {
15679
15951
  const token_content = token.value.trim();
15680
- if (token_content.includes("@lsp-ignore-next")) {
15681
- for (let j = i + 1;j < tokens.length; j++) {
15682
- const next_token = tokens[j];
15683
- if (next_token.type !== "WHITESPACE" && next_token.type !== "COMMENT_LINE" && next_token.type !== "COMMENT_BLOCK" && next_token.type !== "CONTINUATION" && next_token.type !== "STATEMENT_TERMINATOR") {
15684
- this.config.ignored_lines.add(next_token.range.start.line);
15685
- break;
15686
- }
15952
+ const is_standalone_comment = this.is_standalone_comment_token(tokens, i);
15953
+ if (has_ignore_directive(token_content)) {
15954
+ if (is_standalone_comment) {
15955
+ this.ignore_next_non_trivia_line(tokens, i);
15956
+ } else {
15957
+ this.config.ignored_lines.add(token.range.start.line);
15687
15958
  }
15688
- } else if (token_content.includes("@lsp-ignore")) {
15689
- this.config.ignored_lines.add(token.range.start.line);
15690
15959
  }
15691
- const variables_match = token_content.match(/@lsp-variables\s+(.+)/);
15960
+ if (has_ignore_next_directive(token_content)) {
15961
+ this.ignore_next_non_trivia_line(tokens, i);
15962
+ }
15963
+ if (!is_standalone_comment) {
15964
+ continue;
15965
+ }
15966
+ const variables_match = token_content.match(VARIABLES_DIRECTIVE_PATTERN);
15692
15967
  if (variables_match) {
15693
15968
  const var_names = variables_match[1].split(/\s+/).filter((v) => v.length > 0);
15694
15969
  for (const var_name of var_names) {
@@ -15698,37 +15973,31 @@ class SemanticAnalyzer {
15698
15973
  }
15699
15974
  }
15700
15975
  }
15976
+ ignore_next_non_trivia_line(tokens, directive_index) {
15977
+ for (let j = directive_index + 1;j < tokens.length; j++) {
15978
+ const next_token = tokens[j];
15979
+ if (next_token.type !== "WHITESPACE" && next_token.type !== "COMMENT_LINE" && next_token.type !== "COMMENT_BLOCK" && next_token.type !== "CONTINUATION" && next_token.type !== "STATEMENT_TERMINATOR") {
15980
+ this.config.ignored_lines.add(next_token.range.start.line);
15981
+ break;
15982
+ }
15983
+ }
15984
+ }
15701
15985
  parse_declaration_directives_from_tokens(tokens, symbols) {
15702
- const DECLARATION_PATTERN = /@lsp-(local|global|scalar|matrix|program)\s+(.+)/;
15703
- for (const token of tokens) {
15704
- if (token.type !== "COMMENT_LINE" && token.type !== "COMMENT_BLOCK") {
15986
+ for (let i = 0;i < tokens.length; i++) {
15987
+ const token = tokens[i];
15988
+ if (token.type !== "COMMENT_LINE") {
15705
15989
  continue;
15706
15990
  }
15707
- const token_content = token.value;
15708
- if (token.type === "COMMENT_BLOCK") {
15709
- const my_doc = { content: token_content, line_offsets: compute_line_offsets(token_content) };
15710
- const my_line_count = get_line_count(my_doc);
15711
- for (let line_offset = 0;line_offset < my_line_count; line_offset++) {
15712
- const my_line = get_line_text(my_doc, line_offset);
15713
- const my_match = my_line.match(DECLARATION_PATTERN);
15714
- if (my_match) {
15715
- const my_type = my_match[1];
15716
- const the_names = my_match[2].split(/\s+/).filter((n) => n.length > 0);
15717
- const my_actual_line = token.range.start.line + line_offset;
15718
- for (const my_name of the_names) {
15719
- this.register_declaration_directive(my_type, my_name, my_actual_line, symbols);
15720
- }
15721
- }
15722
- }
15723
- } else {
15724
- const my_match = token_content.match(DECLARATION_PATTERN);
15725
- if (my_match) {
15726
- const my_type = my_match[1];
15727
- const the_names = my_match[2].split(/\s+/).filter((n) => n.length > 0);
15728
- const my_actual_line = token.range.start.line;
15729
- for (const my_name of the_names) {
15730
- this.register_declaration_directive(my_type, my_name, my_actual_line, symbols);
15731
- }
15991
+ if (!this.is_standalone_comment_token(tokens, i)) {
15992
+ continue;
15993
+ }
15994
+ const my_match = token.value.match(DECLARATION_DIRECTIVE_PATTERN);
15995
+ if (my_match) {
15996
+ const my_type = my_match[1];
15997
+ const the_names = my_match[2].split(/\s+/).filter((n) => n.length > 0);
15998
+ const my_actual_line = token.range.start.line;
15999
+ for (const my_name of the_names) {
16000
+ this.register_declaration_directive(my_type, my_name, my_actual_line, symbols);
15732
16001
  }
15733
16002
  }
15734
16003
  }
@@ -15807,11 +16076,6 @@ class SemanticAnalyzer {
15807
16076
  this.parse_directive(trivia, node);
15808
16077
  }
15809
16078
  }
15810
- if (this.has_trivia(node) && node.trailingTrivia) {
15811
- for (const trivia of node.trailingTrivia) {
15812
- this.parse_directive(trivia, node);
15813
- }
15814
- }
15815
16079
  if (node.type === "program") {
15816
16080
  for (const child of node.body) {
15817
16081
  this.extract_directives_from_node(child);
@@ -15824,11 +16088,11 @@ class SemanticAnalyzer {
15824
16088
  }
15825
16089
  parse_directive(trivia, following_node) {
15826
16090
  const content = trivia.content.trim();
15827
- if (content.includes("@lsp-ignore-next")) {
16091
+ if (has_ignore_directive(content) || has_ignore_next_directive(content)) {
15828
16092
  const line_to_ignore = following_node.range.start.line;
15829
16093
  this.config.ignored_lines.add(line_to_ignore);
15830
16094
  }
15831
- const variables_match = content.match(/@lsp-variables\s+(.+)/);
16095
+ const variables_match = content.match(VARIABLES_DIRECTIVE_PATTERN);
15832
16096
  if (variables_match) {
15833
16097
  const var_names = variables_match[1].split(/\s+/).filter((v) => v.length > 0);
15834
16098
  for (const var_name of var_names) {
@@ -15836,6 +16100,20 @@ class SemanticAnalyzer {
15836
16100
  }
15837
16101
  }
15838
16102
  }
16103
+ is_standalone_comment_token(tokens, comment_index) {
16104
+ const comment = tokens[comment_index];
16105
+ const line = comment.range.start.line;
16106
+ for (let i = comment_index - 1;i >= 0; i--) {
16107
+ const token = tokens[i];
16108
+ if (token.range.start.line !== line) {
16109
+ break;
16110
+ }
16111
+ if (token.type !== "WHITESPACE") {
16112
+ return false;
16113
+ }
16114
+ }
16115
+ return true;
16116
+ }
15839
16117
  build_symbols(nodes, symbols, current_scope, all_scopes) {
15840
16118
  this.traverse_ast_preorder(nodes, (node, node_index) => {
15841
16119
  this.process_node(node, symbols, current_scope, all_scopes, node_index);
@@ -16322,7 +16600,7 @@ class SemanticAnalyzer {
16322
16600
  this.current_diagnostics.push({
16323
16601
  message: `Missing variable name after storage type \`${node.varlist[0].name}'`,
16324
16602
  range: node.varlist[0].range,
16325
- code: 2004 /* MISSING_VARIABLE_NAME */,
16603
+ code: "MISSING_VARIABLE_NAME" /* MISSING_VARIABLE_NAME */,
16326
16604
  severity: "error"
16327
16605
  });
16328
16606
  return;
@@ -16833,7 +17111,7 @@ class SemanticAnalyzer {
16833
17111
  diagnostics.push({
16834
17112
  message: format_undefined_macro_message(node.scope, node.name),
16835
17113
  range: node.range,
16836
- code: 2001 /* UNDEFINED_MACRO */,
17114
+ code: "UNDEFINED_MACRO" /* UNDEFINED_MACRO */,
16837
17115
  severity: "warning",
16838
17116
  symbol_name: node.name,
16839
17117
  reference_kind: node.scope
@@ -16851,7 +17129,7 @@ class SemanticAnalyzer {
16851
17129
  diagnostics.push({
16852
17130
  message: format_undefined_macro_message(macro_ref.scope, macro_ref.name),
16853
17131
  range: macro_ref.range,
16854
- code: 2001 /* UNDEFINED_MACRO */,
17132
+ code: "UNDEFINED_MACRO" /* UNDEFINED_MACRO */,
16855
17133
  severity: "warning",
16856
17134
  symbol_name: macro_ref.name,
16857
17135
  reference_kind: macro_ref.scope
@@ -16873,7 +17151,7 @@ class SemanticAnalyzer {
16873
17151
  diagnostics.push({
16874
17152
  message: format_undefined_variable_message(var_node.name),
16875
17153
  range: var_node.range,
16876
- code: 2002 /* UNDEFINED_VARIABLE */,
17154
+ code: "UNDEFINED_VARIABLE" /* UNDEFINED_VARIABLE */,
16877
17155
  severity: "information",
16878
17156
  symbol_name: var_node.name,
16879
17157
  reference_kind: "variable"
@@ -17001,7 +17279,7 @@ class SemanticAnalyzer {
17001
17279
  diagnostics.push({
17002
17280
  message: "Invalid character in macro name",
17003
17281
  range: token.range,
17004
- code: 3010 /* INVALID_MACRO_CHAR */,
17282
+ code: "INVALID_MACRO_CHAR" /* INVALID_MACRO_CHAR */,
17005
17283
  severity: "error"
17006
17284
  });
17007
17285
  continue;
@@ -17011,7 +17289,7 @@ class SemanticAnalyzer {
17011
17289
  diagnostics.push({
17012
17290
  message: format_undefined_macro_message("local", macro_name),
17013
17291
  range: token.range,
17014
- code: 2001 /* UNDEFINED_MACRO */,
17292
+ code: "UNDEFINED_MACRO" /* UNDEFINED_MACRO */,
17015
17293
  severity: "warning",
17016
17294
  symbol_name: macro_name,
17017
17295
  reference_kind: "local"
@@ -17030,7 +17308,7 @@ class SemanticAnalyzer {
17030
17308
  diagnostics.push({
17031
17309
  message: "Invalid character in macro name",
17032
17310
  range: token.range,
17033
- code: 3010 /* INVALID_MACRO_CHAR */,
17311
+ code: "INVALID_MACRO_CHAR" /* INVALID_MACRO_CHAR */,
17034
17312
  severity: "error"
17035
17313
  });
17036
17314
  continue;
@@ -17040,7 +17318,7 @@ class SemanticAnalyzer {
17040
17318
  diagnostics.push({
17041
17319
  message: format_undefined_macro_message("global", macro_name),
17042
17320
  range: token.range,
17043
- code: 2001 /* UNDEFINED_MACRO */,
17321
+ code: "UNDEFINED_MACRO" /* UNDEFINED_MACRO */,
17044
17322
  severity: "warning",
17045
17323
  symbol_name: macro_name,
17046
17324
  reference_kind: "global"
@@ -17193,6 +17471,7 @@ var init_analyzer = __esm(() => {
17193
17471
  init_types();
17194
17472
  init_directive_parser();
17195
17473
  init_macro_creating_commands();
17474
+ init_directives();
17196
17475
  STATA_SYSTEM_GLOBALS = new Set([
17197
17476
  "S_DATE",
17198
17477
  "S_TIME",
@@ -17227,7 +17506,9 @@ var init_analyzer = __esm(() => {
17227
17506
  });
17228
17507
 
17229
17508
  // src/context-tracker/types.ts
17230
- var init_types2 = () => {};
17509
+ var init_types2 = __esm(() => {
17510
+ init_types();
17511
+ });
17231
17512
 
17232
17513
  // src/context-tracker/index.ts
17233
17514
  class ContextTracker {
@@ -17236,10 +17517,18 @@ class ContextTracker {
17236
17517
  context_stack = ["stata" /* STATA */];
17237
17518
  document_content = "";
17238
17519
  diagnostics = [];
17520
+ block_comment_continuation_lines = new Set;
17239
17521
  initialize_from_tokens(tokens, document_content) {
17240
17522
  if (document_content !== undefined) {
17241
17523
  this.document_content = document_content;
17242
17524
  }
17525
+ const my_comment_lines = block_comment_lines(this.document_content, tokens);
17526
+ for (const my_token of tokens) {
17527
+ if (!CONTEXT_TRIVIA_TOKEN_TYPES.has(my_token.type)) {
17528
+ my_comment_lines.delete(my_token.range.start.line);
17529
+ }
17530
+ }
17531
+ this.block_comment_continuation_lines = my_comment_lines;
17243
17532
  this.context_ranges = [];
17244
17533
  this.sorted_ranges_cache = null;
17245
17534
  this.context_stack = ["stata" /* STATA */];
@@ -17404,7 +17693,7 @@ class ContextTracker {
17404
17693
  this.diagnostics = [];
17405
17694
  for (const my_range of this.context_ranges) {
17406
17695
  if (!my_range.end_delimiter && !my_range.is_single_line) {
17407
- const my_error_code = my_range.context === "mata" /* MATA */ ? 4001 /* UNCLOSED_MATA_BLOCK */ : 4002 /* UNCLOSED_PYTHON_BLOCK */;
17696
+ const my_error_code = my_range.context === "mata" /* MATA */ ? "UNCLOSED_MATA_BLOCK" /* UNCLOSED_MATA_BLOCK */ : "UNCLOSED_PYTHON_BLOCK" /* UNCLOSED_PYTHON_BLOCK */;
17408
17697
  this.diagnostics.push({
17409
17698
  message: my_range.context === "mata" /* MATA */ ? 'Unclosed mata block - missing "end" command' : 'Unclosed python block - missing "end" command',
17410
17699
  range: my_range.start_delimiter.range,
@@ -17421,6 +17710,9 @@ class ContextTracker {
17421
17710
  const my_line_count = get_line_count(my_doc);
17422
17711
  const my_valid_end_lines = this.find_valid_end_lines(my_doc);
17423
17712
  for (let my_line_number = 0;my_line_number < my_line_count; my_line_number++) {
17713
+ if (this.block_comment_continuation_lines.has(my_line_number)) {
17714
+ continue;
17715
+ }
17424
17716
  const my_line = get_line_text(my_doc, my_line_number);
17425
17717
  const my_code_part = this.extract_code_before_comment(my_line);
17426
17718
  const my_code_trimmed = my_code_part.trim();
@@ -17454,7 +17746,7 @@ class ContextTracker {
17454
17746
  }
17455
17747
  },
17456
17748
  severity: "error",
17457
- code: 4003 /* UNEXPECTED_END */
17749
+ code: "UNEXPECTED_END" /* UNEXPECTED_END */
17458
17750
  });
17459
17751
  }
17460
17752
  }
@@ -17469,7 +17761,7 @@ class ContextTracker {
17469
17761
  }
17470
17762
  },
17471
17763
  severity: "error",
17472
- code: 4005 /* MISMATCHED_END_PYTHON */
17764
+ code: "MISMATCHED_END_PYTHON" /* MISMATCHED_END_PYTHON */
17473
17765
  });
17474
17766
  }
17475
17767
  if (my_code_trimmed === "end mata") {
@@ -17483,7 +17775,7 @@ class ContextTracker {
17483
17775
  }
17484
17776
  },
17485
17777
  severity: "warning",
17486
- code: 4007 /* INVALID_DELIMITER_POSITION */
17778
+ code: "INVALID_DELIMITER_POSITION" /* INVALID_DELIMITER_POSITION */
17487
17779
  });
17488
17780
  }
17489
17781
  if (my_code_trimmed.startsWith("end ") && my_code_trimmed !== "end python") {
@@ -17502,7 +17794,7 @@ class ContextTracker {
17502
17794
  }
17503
17795
  },
17504
17796
  severity: "error",
17505
- code: 4007 /* INVALID_DELIMITER_POSITION */
17797
+ code: "INVALID_DELIMITER_POSITION" /* INVALID_DELIMITER_POSITION */
17506
17798
  });
17507
17799
  }
17508
17800
  }
@@ -17532,6 +17824,9 @@ class ContextTracker {
17532
17824
  const my_embedded_stack = [];
17533
17825
  const my_line_count = get_line_count(doc);
17534
17826
  for (let my_line_number = 0;my_line_number < my_line_count; my_line_number++) {
17827
+ if (this.block_comment_continuation_lines.has(my_line_number)) {
17828
+ continue;
17829
+ }
17535
17830
  const my_line = get_line_text(doc, my_line_number);
17536
17831
  const my_code_part = this.extract_code_before_comment(my_line);
17537
17832
  const my_code_trimmed = my_code_part.trim();
@@ -17686,27 +17981,27 @@ class ContextTracker {
17686
17981
  get_error_recovery_suggestions(error) {
17687
17982
  const my_suggestions = [];
17688
17983
  switch (error.code) {
17689
- case 4001 /* UNCLOSED_MATA_BLOCK */:
17984
+ case "UNCLOSED_MATA_BLOCK" /* UNCLOSED_MATA_BLOCK */:
17690
17985
  my_suggestions.push('Add "end" command to close the mata block');
17691
17986
  my_suggestions.push('Ensure "end" is on its own line at the start of a statement');
17692
17987
  break;
17693
- case 4002 /* UNCLOSED_PYTHON_BLOCK */:
17988
+ case "UNCLOSED_PYTHON_BLOCK" /* UNCLOSED_PYTHON_BLOCK */:
17694
17989
  my_suggestions.push('Add "end" command to close the python block');
17695
17990
  my_suggestions.push('Ensure "end" is on its own line at the start of a statement');
17696
17991
  break;
17697
- case 4003 /* UNEXPECTED_END */:
17992
+ case "UNEXPECTED_END" /* UNEXPECTED_END */:
17698
17993
  my_suggestions.push('Remove "end" command or add a corresponding program, mata, python, or input block');
17699
17994
  my_suggestions.push('"end" can only be used to close a program, mata, python, or input block');
17700
17995
  break;
17701
- case 4005 /* MISMATCHED_END_PYTHON */:
17996
+ case "MISMATCHED_END_PYTHON" /* MISMATCHED_END_PYTHON */:
17702
17997
  my_suggestions.push('Remove "end python" command or add a corresponding "python" block');
17703
17998
  my_suggestions.push('"end python" can only be used to close a python block');
17704
17999
  break;
17705
- case 4007 /* INVALID_DELIMITER_POSITION */:
18000
+ case "INVALID_DELIMITER_POSITION" /* INVALID_DELIMITER_POSITION */:
17706
18001
  my_suggestions.push('Use "end" to close mata blocks, not "end mata"');
17707
18002
  my_suggestions.push("Ensure block delimiters are at statement boundaries");
17708
18003
  break;
17709
- case 4006 /* NESTED_BLOCK_ERROR */:
18004
+ case "NESTED_BLOCK_ERROR" /* NESTED_BLOCK_ERROR */:
17710
18005
  my_suggestions.push("Check that nested blocks are properly closed in the correct order");
17711
18006
  my_suggestions.push("Inner blocks must be closed before outer blocks");
17712
18007
  break;
@@ -17720,6 +18015,9 @@ class ContextTracker {
17720
18015
  const my_doc = { content: this.document_content, line_offsets: compute_line_offsets(this.document_content) };
17721
18016
  const my_line_count = get_line_count(my_doc);
17722
18017
  for (let my_i = start_line + 1;my_i < my_line_count; my_i++) {
18018
+ if (this.block_comment_continuation_lines.has(my_i)) {
18019
+ continue;
18020
+ }
17723
18021
  const my_line = get_line_text(my_doc, my_i);
17724
18022
  const my_code_part = this.extract_code_before_comment(my_line);
17725
18023
  const my_code_trimmed = my_code_part.trim();
@@ -17778,9 +18076,19 @@ end // Correct order`
17778
18076
  ];
17779
18077
  }
17780
18078
  }
18079
+ var CONTEXT_TRIVIA_TOKEN_TYPES;
17781
18080
  var init_context_tracker = __esm(() => {
17782
18081
  init_types2();
17783
18082
  init_types();
18083
+ init_block_comment_utils();
18084
+ CONTEXT_TRIVIA_TOKEN_TYPES = new Set([
18085
+ "COMMENT_LINE",
18086
+ "COMMENT_BLOCK",
18087
+ "CONTINUATION",
18088
+ "WHITESPACE",
18089
+ "STATEMENT_TERMINATOR",
18090
+ "EOF"
18091
+ ]);
17784
18092
  });
17785
18093
 
17786
18094
  // src/utils/parse-timeout.ts
@@ -18189,7 +18497,7 @@ class DocumentStore {
18189
18497
  const directive_parser = new DirectiveParser;
18190
18498
  let resolved_working_directory;
18191
18499
  try {
18192
- const directive_result = directive_parser.parse(content, uri);
18500
+ const directive_result = directive_parser.parse(content, uri, lex_result.result.tokens);
18193
18501
  if (this.scope_resolver) {
18194
18502
  this.scope_resolver.sync_backward_directive_dependencies(uri, directive_result.directives);
18195
18503
  }
@@ -18251,7 +18559,7 @@ class DocumentStore {
18251
18559
  let all_forward_calls = analyze_result.result.forward_calls;
18252
18560
  try {
18253
18561
  const directive_parser2 = new DirectiveParser;
18254
- const directive_result = directive_parser2.parse_forward_call_directives(content, uri);
18562
+ const directive_result = directive_parser2.parse_forward_call_directives(content, uri, lex_result.result.tokens);
18255
18563
  const directive_forward_calls = directive_result.forward_calls.map((d) => ({
18256
18564
  type: d.type,
18257
18565
  raw_path: d.raw_path,
@@ -18382,14 +18690,16 @@ class DocumentStore {
18382
18690
  message: error.message,
18383
18691
  severity: import_vscode_languageserver.DiagnosticSeverity.Error,
18384
18692
  code: error.code,
18385
- source: "sight"
18693
+ source: "sight",
18694
+ ...diagnostic_code_description_fields(error.code)
18386
18695
  })),
18387
18696
  ...parser_errors.map((error) => ({
18388
18697
  range: error.range,
18389
18698
  message: error.message,
18390
18699
  severity: import_vscode_languageserver.DiagnosticSeverity.Error,
18391
18700
  code: error.code,
18392
- source: "sight"
18701
+ source: "sight",
18702
+ ...diagnostic_code_description_fields(error.code)
18393
18703
  })),
18394
18704
  ...analyzer_diagnostics.map((diag) => ({
18395
18705
  range: diag.range,
@@ -18397,6 +18707,7 @@ class DocumentStore {
18397
18707
  severity: diag.severity === "error" ? import_vscode_languageserver.DiagnosticSeverity.Error : diag.severity === "warning" ? import_vscode_languageserver.DiagnosticSeverity.Warning : diag.severity === "information" ? import_vscode_languageserver.DiagnosticSeverity.Information : import_vscode_languageserver.DiagnosticSeverity.Hint,
18398
18708
  code: diag.code,
18399
18709
  source: "sight",
18710
+ ...diagnostic_code_description_fields(diag.code),
18400
18711
  ...undefined_symbol_data_fields(diag)
18401
18712
  }))
18402
18713
  ];
@@ -18417,6 +18728,7 @@ class DocumentStore {
18417
18728
  }
18418
18729
  var import_vscode_languageserver;
18419
18730
  var init_document_store = __esm(() => {
18731
+ init_diagnostic_code_description();
18420
18732
  init_lexer();
18421
18733
  init_parser();
18422
18734
  init_analyzer();
@@ -18537,7 +18849,7 @@ class ForwardScopeResolver {
18537
18849
  message: `${source_prefix}Maximum forward resolution ` + `depth (${resolved_config.max_forward_depth}) ` + `exceeded`,
18538
18850
  severity: max_depth_setting,
18539
18851
  kind: "truncation",
18540
- code: 7002 /* CROSS_FILE_TRUNCATED */,
18852
+ code: "CROSS_FILE_TRUNCATED" /* CROSS_FILE_TRUNCATED */,
18541
18853
  range: anchor_range,
18542
18854
  source: {
18543
18855
  source_file: path4.basename(URI.parse(anchor_uri).fsPath),
@@ -18562,7 +18874,7 @@ class ForwardScopeResolver {
18562
18874
  range: my_call.range,
18563
18875
  severity: "warning",
18564
18876
  kind: "path_case_mismatch",
18565
- code: 7001 /* PATH_CASE_MISMATCH */,
18877
+ code: "PATH_CASE_MISMATCH" /* PATH_CASE_MISMATCH */,
18566
18878
  case_mismatch_seed_dir: my_path_result.seed_dir,
18567
18879
  source: {
18568
18880
  source_file: path4.basename(URI.parse(file_uri).fsPath),
@@ -18578,6 +18890,7 @@ class ForwardScopeResolver {
18578
18890
  range: my_call.range,
18579
18891
  severity: "warning",
18580
18892
  kind: "missing_file",
18893
+ code: "CROSS_FILE_MISSING_FILE" /* CROSS_FILE_MISSING_FILE */,
18581
18894
  source: {
18582
18895
  source_file: my_source_filename,
18583
18896
  source_line: my_call.call_site_line,
@@ -18627,6 +18940,8 @@ class ForwardScopeResolver {
18627
18940
  message: `${source_prefix}Cannot read file: ${my_call.raw_path}${error_suffix}`,
18628
18941
  range: my_call.range,
18629
18942
  severity: "warning",
18943
+ kind: "missing_file",
18944
+ code: "CROSS_FILE_MISSING_FILE" /* CROSS_FILE_MISSING_FILE */,
18630
18945
  source: {
18631
18946
  source_file: source_filename,
18632
18947
  source_line: my_call.call_site_line,
@@ -19297,19 +19612,17 @@ class ScopeResolver {
19297
19612
  const total_lines = get_line_count(doc);
19298
19613
  return line_number >= 0 && line_number < total_lines;
19299
19614
  }
19300
- validate_call_statement(line_content) {
19301
- const my_trimmed = line_content.trim();
19302
- const command_match = my_trimmed.match(DO_INCLUDE_PATTERN2);
19303
- if (command_match) {
19304
- return command_match[1];
19305
- }
19306
- if (my_trimmed.startsWith("*") || my_trimmed.startsWith("//")) {
19307
- const directive_match = my_trimmed.match(DIRECTIVE_PATTERN2);
19308
- if (directive_match) {
19309
- return directive_match[1];
19310
- }
19615
+ validate_call_statement(parent_content, line_number, block_ranges) {
19616
+ const doc = {
19617
+ content: parent_content,
19618
+ line_offsets: compute_line_offsets(parent_content)
19619
+ };
19620
+ const line_content = get_line_text(doc, line_number);
19621
+ const leading_col = line_content.search(/\S/);
19622
+ if (leading_col >= 0 && position_in_block_comment(line_number, leading_col, block_ranges)) {
19623
+ return;
19311
19624
  }
19312
- return;
19625
+ return this.directive_parser.classify_call_line(line_content);
19313
19626
  }
19314
19627
  detect_mixed_call_types(parent_content, child_filename) {
19315
19628
  const all_call_sites = this.directive_parser.find_all_call_sites_for_file(parent_content, child_filename);
@@ -19326,7 +19639,7 @@ class ScopeResolver {
19326
19639
  maybe_emit_included_by_mismatch(directive_type, detected_call_type, range, parent_filename, source_line, diagnostics) {
19327
19640
  if (directive_type === "included-by" && detected_call_type !== "include") {
19328
19641
  diagnostics.push({
19329
- message: `Directive @lsp-included-by used but caller uses ${detected_call_type} (not include). Local macros will not be inherited.`,
19642
+ message: `Directive sight: included-by used but caller uses ${detected_call_type} (not include). Local macros will not be inherited.`,
19330
19643
  range,
19331
19644
  severity: "warning",
19332
19645
  source: {
@@ -19342,7 +19655,7 @@ class ScopeResolver {
19342
19655
  const call_site_severity = config.diagnostics?.call_site_identification ?? "information";
19343
19656
  if (call_site_severity !== "off") {
19344
19657
  diagnostics.push({
19345
- message: `Directive @lsp-done-by used but caller uses include. Full inheritance (including local macros) will occur.`,
19658
+ message: `Directive sight: done-by used but caller uses include. Full inheritance (including local macros) will occur.`,
19346
19659
  range,
19347
19660
  severity: call_site_severity,
19348
19661
  source: {
@@ -19384,7 +19697,7 @@ class ScopeResolver {
19384
19697
  if (has_done_by && has_included_by) {
19385
19698
  const my_range = the_group.find((d) => d.type === "included-by")?.range ?? the_group[0].range;
19386
19699
  diagnostics.push({
19387
- message: "Both @lsp-done-by and @lsp-included-by reference the same parent; " + "treating as included-by (full inheritance).",
19700
+ message: "Both sight: done-by and sight: included-by reference the same parent; " + "treating as included-by (full inheritance).",
19388
19701
  range: my_range,
19389
19702
  severity: "warning"
19390
19703
  });
@@ -19441,7 +19754,7 @@ class ScopeResolver {
19441
19754
  range: directive.range,
19442
19755
  severity: "warning",
19443
19756
  kind: "path_case_mismatch",
19444
- code: 7001 /* PATH_CASE_MISMATCH */,
19757
+ code: "PATH_CASE_MISMATCH" /* PATH_CASE_MISMATCH */,
19445
19758
  case_mismatch_seed_dir: seed_dir,
19446
19759
  source: {
19447
19760
  source_file: path5.basename(URI.parse(child_uri).fsPath),
@@ -19710,7 +20023,7 @@ class ScopeResolver {
19710
20023
  range: chain_range,
19711
20024
  severity: max_depth_setting,
19712
20025
  kind: "truncation",
19713
- code: 7002 /* CROSS_FILE_TRUNCATED */,
20026
+ code: "CROSS_FILE_TRUNCATED" /* CROSS_FILE_TRUNCATED */,
19714
20027
  source: {
19715
20028
  source_file: parent_basename,
19716
20029
  ...has_known_call_site ? { source_line: call_site_line } : {},
@@ -19827,7 +20140,7 @@ class ScopeResolver {
19827
20140
  range: default_range,
19828
20141
  severity: max_depth_severity,
19829
20142
  kind: "truncation",
19830
- code: 7002 /* CROSS_FILE_TRUNCATED */,
20143
+ code: "CROSS_FILE_TRUNCATED" /* CROSS_FILE_TRUNCATED */,
19831
20144
  source: {
19832
20145
  source_file: source_filename,
19833
20146
  source_line: 0,
@@ -19873,6 +20186,7 @@ class ScopeResolver {
19873
20186
  range: my_directive.range,
19874
20187
  severity: "warning",
19875
20188
  kind: "missing_file",
20189
+ code: "CROSS_FILE_MISSING_FILE" /* CROSS_FILE_MISSING_FILE */,
19876
20190
  source: {
19877
20191
  source_file: source_filename,
19878
20192
  original_range: my_directive.range
@@ -19889,6 +20203,7 @@ class ScopeResolver {
19889
20203
  let my_call_site_line;
19890
20204
  let effective_call_type = my_directive.type === "included-by" ? "include" : "do";
19891
20205
  if (my_directive.call_site) {
20206
+ const my_block_ranges = block_comment_ranges(my_parent_content);
19892
20207
  if (my_directive.call_site.type === "line") {
19893
20208
  my_call_site_line = my_directive.call_site.value - 1;
19894
20209
  if (!this.is_line_in_bounds(my_call_site_line, my_parent_content)) {
@@ -19905,12 +20220,10 @@ class ScopeResolver {
19905
20220
  });
19906
20221
  my_call_site_line = config.assume_call_site === "end" ? Number.MAX_SAFE_INTEGER : 0;
19907
20222
  } else {
19908
- const doc = { content: my_parent_content, line_offsets: compute_line_offsets(my_parent_content) };
19909
- const line_content = get_line_text(doc, my_call_site_line);
19910
- const call_validation = this.validate_call_statement(line_content);
20223
+ const call_validation = this.validate_call_statement(my_parent_content, my_call_site_line, my_block_ranges);
19911
20224
  if (!call_validation) {
19912
20225
  diagnostics.push({
19913
- message: `Specified line=${my_directive.call_site.value} does not contain a do/run/include command or @lsp-do/run/include directive.`,
20226
+ message: `Specified line=${my_directive.call_site.value} does not contain a do/run/include command or forward directive.`,
19914
20227
  range: my_directive.range,
19915
20228
  severity: "warning",
19916
20229
  source: {
@@ -19926,7 +20239,7 @@ class ScopeResolver {
19926
20239
  }
19927
20240
  }
19928
20241
  } else {
19929
- const my_match_line = this.directive_parser.find_match_line(my_parent_content, my_directive.call_site.value);
20242
+ const my_match_line = this.directive_parser.find_match_line(my_parent_content, my_directive.call_site.value, my_block_ranges);
19930
20243
  if (my_match_line === undefined) {
19931
20244
  diagnostics.push({
19932
20245
  message: `Match string "${my_directive.call_site.value}" not found in parent file "${parent_filename}". Using default call site assumption.`,
@@ -19940,9 +20253,7 @@ class ScopeResolver {
19940
20253
  my_call_site_line = config.assume_call_site === "end" ? Number.MAX_SAFE_INTEGER : 0;
19941
20254
  } else {
19942
20255
  my_call_site_line = my_match_line;
19943
- const doc = { content: my_parent_content, line_offsets: compute_line_offsets(my_parent_content) };
19944
- const line_content = get_line_text(doc, my_call_site_line);
19945
- const matched_call_type = this.validate_call_statement(line_content);
20256
+ const matched_call_type = this.validate_call_statement(my_parent_content, my_call_site_line, my_block_ranges);
19946
20257
  if (matched_call_type) {
19947
20258
  effective_call_type = matched_call_type;
19948
20259
  this.maybe_emit_included_by_mismatch(my_directive.type, matched_call_type, my_directive.range, parent_filename, my_call_site_line, diagnostics);
@@ -20089,7 +20400,7 @@ class ScopeResolver {
20089
20400
  const effective_working_directory = own_working_directory ?? inherited_working_directory;
20090
20401
  const my_analysis = this.analyzer.analyze(my_parse_result.ast, uri, undefined, {
20091
20402
  working_directory: effective_working_directory
20092
- });
20403
+ }, my_lex_result.tokens);
20093
20404
  const directive_forward_calls = (my_directive_result.forward_calls ?? []).map((d) => ({
20094
20405
  type: d.type,
20095
20406
  raw_path: d.raw_path,
@@ -20857,7 +21168,7 @@ class ScopeResolver {
20857
21168
  this.reset_reverse_deps();
20858
21169
  }
20859
21170
  }
20860
- var DEFAULT_CONFIG2, DO_INCLUDE_PATTERN2, DIRECTIVE_PATTERN2;
21171
+ var DEFAULT_CONFIG2;
20861
21172
  var init_scope_resolver = __esm(() => {
20862
21173
  init_esm();
20863
21174
  init_types();
@@ -20867,8 +21178,8 @@ var init_scope_resolver = __esm(() => {
20867
21178
  init_analyzer();
20868
21179
  init_logger();
20869
21180
  init_workspace_roots();
20870
- init_stata_call_patterns();
20871
21181
  init_file_path_utils();
21182
+ init_block_comment_utils();
20872
21183
  init_visible_symbols();
20873
21184
  DEFAULT_CONFIG2 = {
20874
21185
  assume_call_site: "end",
@@ -20876,8 +21187,6 @@ var init_scope_resolver = __esm(() => {
20876
21187
  max_forward_depth: 10,
20877
21188
  max_chain_depth: 20
20878
21189
  };
20879
- DO_INCLUDE_PATTERN2 = build_do_include_pattern("prefix");
20880
- DIRECTIVE_PATTERN2 = /@lsp-(do|run|include):?\s+/;
20881
21190
  });
20882
21191
 
20883
21192
  // src/utils/include-expander.ts
@@ -21582,7 +21891,7 @@ var init_indexer = __esm(() => {
21582
21891
  const lexResult = this.lexer.tokenize(content);
21583
21892
  const parseResult = this.parser.parse(lexResult.tokens);
21584
21893
  const workspace_root = get_workspace_root_for_path(this.workspace_roots, file_path);
21585
- const analyzeResult = this.analyzer.analyze(parseResult.ast, file_uri, undefined);
21894
+ const analyzeResult = this.analyzer.analyze(parseResult.ast, file_uri, undefined, undefined, lexResult.tokens);
21586
21895
  const own_working_directory = directive_result.working_directory ? resolve_working_directory_directive(directive_result.working_directory, workspace_root) : undefined;
21587
21896
  let effective_working_directory = own_working_directory;
21588
21897
  if (own_working_directory === undefined && this.scope_resolver) {
@@ -22189,13 +22498,13 @@ class IndentationDiagnosticAnalyzer {
22189
22498
  }
22190
22499
  const indent_size = config.formatting?.indentSize ?? 4;
22191
22500
  const stataRanges = this.getStataRanges(document);
22192
- const block_comment_lines = this.compute_block_comment_lines(lines);
22501
+ const block_comment_lines2 = this.compute_block_comment_lines(lines, document.tokens);
22193
22502
  const continuation_lines = document.tokens ? this.compute_continuation_lines(document.tokens) : new Set;
22194
22503
  for (const range of stataRanges) {
22195
- diagnostics.push(...this.find_comment_indentation_issues(lines, range, block_comment_lines, indent_size));
22196
- diagnostics.push(...this.find_block_indentation_issues(document, lines, range, block_comment_lines, indent_size, continuation_lines));
22504
+ diagnostics.push(...this.find_comment_indentation_issues(lines, range, block_comment_lines2, indent_size));
22505
+ diagnostics.push(...this.find_block_indentation_issues(document, lines, range, block_comment_lines2, indent_size, continuation_lines));
22197
22506
  const expected_depths = this.compute_expected_depths(document, range);
22198
- diagnostics.push(...this.find_unnecessary_indentation_issues(document, lines, range, block_comment_lines, indent_size, expected_depths, continuation_lines));
22507
+ diagnostics.push(...this.find_unnecessary_indentation_issues(document, lines, range, block_comment_lines2, indent_size, expected_depths, continuation_lines));
22199
22508
  }
22200
22509
  return diagnostics;
22201
22510
  }
@@ -22246,10 +22555,10 @@ class IndentationDiagnosticAnalyzer {
22246
22555
  is_continuation_line(lineIndex, continuation_lines) {
22247
22556
  return continuation_lines.has(lineIndex);
22248
22557
  }
22249
- find_comment_indentation_issues(lines, range, block_comment_lines, indent_size) {
22558
+ find_comment_indentation_issues(lines, range, block_comment_lines2, indent_size) {
22250
22559
  const diagnostics = [];
22251
22560
  for (let i = range.start;i < range.end && i < lines.length - 1; i++) {
22252
- if (block_comment_lines.has(i) || block_comment_lines.has(i + 1)) {
22561
+ if (block_comment_lines2.has(i) || block_comment_lines2.has(i + 1)) {
22253
22562
  continue;
22254
22563
  }
22255
22564
  const line = lines[i];
@@ -22265,17 +22574,18 @@ class IndentationDiagnosticAnalyzer {
22265
22574
  range: import_node.Range.create(import_node.Position.create(i + 1, 0), import_node.Position.create(i + 1, nextIndent)),
22266
22575
  message: "Line appears unnecessarily indented after comment. Use Format Document to fix.",
22267
22576
  source: "sight",
22268
- code: 5001 /* UNNECESSARY_INDENTATION */
22577
+ code: "UNNECESSARY_INDENTATION" /* UNNECESSARY_INDENTATION */,
22578
+ ...diagnostic_code_description_fields("UNNECESSARY_INDENTATION" /* UNNECESSARY_INDENTATION */)
22269
22579
  });
22270
22580
  }
22271
22581
  }
22272
22582
  }
22273
22583
  return diagnostics;
22274
22584
  }
22275
- find_block_indentation_issues(document, lines, range, block_comment_lines, indent_size, continuation_lines) {
22585
+ find_block_indentation_issues(document, lines, range, block_comment_lines2, indent_size, continuation_lines) {
22276
22586
  const diagnostics = [];
22277
22587
  for (let i = range.start;i <= range.end && i < lines.length; i++) {
22278
- if (block_comment_lines.has(i)) {
22588
+ if (block_comment_lines2.has(i)) {
22279
22589
  continue;
22280
22590
  }
22281
22591
  const line = lines[i];
@@ -22285,7 +22595,7 @@ class IndentationDiagnosticAnalyzer {
22285
22595
  const braceIndent = this.get_statement_indentation(lines, i, range.start, indent_size, continuation_lines);
22286
22596
  let braceDepth = 1;
22287
22597
  for (let j = i + 1;j <= range.end && j < lines.length && braceDepth > 0; j++) {
22288
- if (block_comment_lines.has(j)) {
22598
+ if (block_comment_lines2.has(j)) {
22289
22599
  continue;
22290
22600
  }
22291
22601
  const innerLine = lines[j];
@@ -22315,7 +22625,8 @@ class IndentationDiagnosticAnalyzer {
22315
22625
  range: import_node.Range.create(import_node.Position.create(j, 0), import_node.Position.create(j, innerIndent)),
22316
22626
  message: "Line should be indented inside brace block. Use Format Document to fix.",
22317
22627
  source: "sight",
22318
- code: 5002 /* MISSING_INDENTATION */
22628
+ code: "MISSING_INDENTATION" /* MISSING_INDENTATION */,
22629
+ ...diagnostic_code_description_fields("MISSING_INDENTATION" /* MISSING_INDENTATION */)
22319
22630
  });
22320
22631
  }
22321
22632
  }
@@ -22336,35 +22647,51 @@ class IndentationDiagnosticAnalyzer {
22336
22647
  }
22337
22648
  return false;
22338
22649
  }
22339
- compute_block_comment_lines(lines) {
22340
- const block_comment_lines = new Set;
22341
- let in_block_comment = false;
22650
+ compute_block_comment_lines(lines, tokens) {
22651
+ if (tokens && tokens.length > 0) {
22652
+ return this.block_comment_lines_from_tokens(tokens);
22653
+ }
22654
+ const block_comment_lines2 = new Set;
22655
+ let block_comment_depth = 0;
22342
22656
  for (let i = 0;i < lines.length; i++) {
22343
22657
  const line = lines[i];
22344
22658
  let j = 0;
22345
22659
  while (j < line.length) {
22346
- if (!in_block_comment) {
22347
- if (j + 1 < line.length && line[j] === "/" && line[j + 1] === "*") {
22348
- in_block_comment = true;
22349
- block_comment_lines.add(i);
22350
- j += 2;
22351
- continue;
22352
- }
22353
- } else {
22354
- block_comment_lines.add(i);
22660
+ if (j + 1 < line.length && line[j] === "/" && line[j + 1] === "*") {
22661
+ block_comment_depth++;
22662
+ block_comment_lines2.add(i);
22663
+ j += 2;
22664
+ continue;
22665
+ }
22666
+ if (block_comment_depth > 0) {
22667
+ block_comment_lines2.add(i);
22355
22668
  if (j + 1 < line.length && line[j] === "*" && line[j + 1] === "/") {
22356
- in_block_comment = false;
22669
+ block_comment_depth--;
22357
22670
  j += 2;
22358
22671
  continue;
22359
22672
  }
22360
22673
  }
22361
22674
  j++;
22362
22675
  }
22363
- if (in_block_comment) {
22364
- block_comment_lines.add(i);
22676
+ if (block_comment_depth > 0) {
22677
+ block_comment_lines2.add(i);
22365
22678
  }
22366
22679
  }
22367
- return block_comment_lines;
22680
+ return block_comment_lines2;
22681
+ }
22682
+ block_comment_lines_from_tokens(tokens) {
22683
+ const the_block_comment_lines = new Set;
22684
+ for (const my_token of tokens) {
22685
+ const my_spans_lines = my_token.range.end.line > my_token.range.start.line;
22686
+ const my_is_multiline_comment = my_token.type === "COMMENT_BLOCK" || my_token.type === "COMMENT_LINE" && my_spans_lines;
22687
+ if (!my_is_multiline_comment) {
22688
+ continue;
22689
+ }
22690
+ for (let my_line = my_token.range.start.line;my_line <= my_token.range.end.line; my_line++) {
22691
+ the_block_comment_lines.add(my_line);
22692
+ }
22693
+ }
22694
+ return the_block_comment_lines;
22368
22695
  }
22369
22696
  get_statement_indentation(lines, lineIndex, rangeStart, indent_size, continuation_lines) {
22370
22697
  let current_index = lineIndex;
@@ -22473,8 +22800,8 @@ class IndentationDiagnosticAnalyzer {
22473
22800
  is_block_node_type(node) {
22474
22801
  return node.type === "program" || node.type === "if" || node.type === "else" || node.type === "foreach" || node.type === "forvalues" || node.type === "while" || node.type === "frame";
22475
22802
  }
22476
- should_skip_unnecessary_check(line, lineIndex, block_comment_lines, continuation_lines) {
22477
- if (block_comment_lines.has(lineIndex)) {
22803
+ should_skip_unnecessary_check(line, lineIndex, block_comment_lines2, continuation_lines) {
22804
+ if (block_comment_lines2.has(lineIndex)) {
22478
22805
  return true;
22479
22806
  }
22480
22807
  const trimmed = line.trim();
@@ -22489,11 +22816,11 @@ class IndentationDiagnosticAnalyzer {
22489
22816
  }
22490
22817
  return false;
22491
22818
  }
22492
- find_unnecessary_indentation_issues(document, lines, range, block_comment_lines, indent_size, expected_depths, continuation_lines) {
22819
+ find_unnecessary_indentation_issues(document, lines, range, block_comment_lines2, indent_size, expected_depths, continuation_lines) {
22493
22820
  const diagnostics = [];
22494
22821
  for (let i = range.start;i <= range.end && i < lines.length; i++) {
22495
22822
  const line = lines[i];
22496
- if (this.should_skip_unnecessary_check(line, i, block_comment_lines, continuation_lines)) {
22823
+ if (this.should_skip_unnecessary_check(line, i, block_comment_lines2, continuation_lines)) {
22497
22824
  continue;
22498
22825
  }
22499
22826
  const actual_indent = this.get_line_indentation(line, indent_size);
@@ -22505,7 +22832,8 @@ class IndentationDiagnosticAnalyzer {
22505
22832
  range: import_node.Range.create(import_node.Position.create(i, 0), import_node.Position.create(i, actual_indent)),
22506
22833
  message: "Line appears unnecessarily indented. Use Format Document to fix.",
22507
22834
  source: "sight",
22508
- code: 5001 /* UNNECESSARY_INDENTATION */
22835
+ code: "UNNECESSARY_INDENTATION" /* UNNECESSARY_INDENTATION */,
22836
+ ...diagnostic_code_description_fields("UNNECESSARY_INDENTATION" /* UNNECESSARY_INDENTATION */)
22509
22837
  });
22510
22838
  }
22511
22839
  }
@@ -22516,6 +22844,7 @@ var import_node, CONTROL_FLOW_RE, FIRST_WORD_RE;
22516
22844
  var init_indentation_diagnostics = __esm(() => {
22517
22845
  init_types2();
22518
22846
  init_types();
22847
+ init_diagnostic_code_description();
22519
22848
  import_node = __toESM(require_main4(), 1);
22520
22849
  CONTROL_FLOW_RE = /^(if|foreach|while|program|mata|python)\b/;
22521
22850
  FIRST_WORD_RE = /^(\w+)\b/;
@@ -22525,9 +22854,10 @@ var init_indentation_diagnostics = __esm(() => {
22525
22854
  class OperatorSequenceAnalyzer {
22526
22855
  analyze(document, config) {
22527
22856
  const malformed_severity = config.diagnostics?.severity?.malformedOperator ?? "warning";
22857
+ const spaced_compound_severity = config.diagnostics?.severity?.spacedCompoundOperator ?? "information";
22528
22858
  const invalid_severity = config.diagnostics?.severity?.invalidOperatorSequence ?? "error";
22529
22859
  const cstyle_severity = config.diagnostics?.severity?.cStyleLogicalInControlFlow ?? "information";
22530
- if (malformed_severity === "off" && invalid_severity === "off" && cstyle_severity === "off") {
22860
+ if (malformed_severity === "off" && spaced_compound_severity === "off" && invalid_severity === "off" && cstyle_severity === "off") {
22531
22861
  return [];
22532
22862
  }
22533
22863
  const the_tokens = document.tokens;
@@ -22562,7 +22892,10 @@ class OperatorSequenceAnalyzer {
22562
22892
  }
22563
22893
  let config_severity;
22564
22894
  switch (pair_result.kind) {
22565
- case "suggestible":
22895
+ case "spaced_compound":
22896
+ config_severity = spaced_compound_severity;
22897
+ break;
22898
+ case "malformed":
22566
22899
  config_severity = malformed_severity;
22567
22900
  break;
22568
22901
  case "invalid":
@@ -22582,7 +22915,8 @@ class OperatorSequenceAnalyzer {
22582
22915
  message: pair_result.message,
22583
22916
  severity,
22584
22917
  source: "sight",
22585
- code: pair_result.code
22918
+ code: pair_result.code,
22919
+ ...diagnostic_code_description_fields(pair_result.code)
22586
22920
  };
22587
22921
  the_diagnostics.push(diagnostic);
22588
22922
  i = next_index;
@@ -22620,16 +22954,28 @@ class OperatorSequenceAnalyzer {
22620
22954
  const first_value = first_token.value;
22621
22955
  const second_value = second_token.value;
22622
22956
  const pair_key = `${first_value} ${second_value}`;
22623
- const suggested_compound = SUGGESTIBLE_PAIRS.get(pair_key);
22624
- if (suggested_compound) {
22957
+ const spaced_compound = SPACED_COMPOUND_PAIRS.get(pair_key);
22958
+ if (spaced_compound) {
22959
+ return {
22960
+ kind: "spaced_compound",
22961
+ first_token,
22962
+ second_token,
22963
+ pair_key,
22964
+ message: `Spaced compound operator '${pair_key}'. Stata treats this as ` + `'${spaced_compound}'; consider writing '${spaced_compound}'.`,
22965
+ default_severity: import_node2.DiagnosticSeverity.Information,
22966
+ code: "SPACED_COMPOUND_OPERATOR" /* SPACED_COMPOUND_OPERATOR */
22967
+ };
22968
+ }
22969
+ const malformed_suggestion = MALFORMED_OPERATOR_PAIRS.get(pair_key);
22970
+ if (malformed_suggestion) {
22625
22971
  return {
22626
- kind: "suggestible",
22972
+ kind: "malformed",
22627
22973
  first_token,
22628
22974
  second_token,
22629
22975
  pair_key,
22630
- message: `Malformed operator '${pair_key}'. Did you mean '${suggested_compound}'?`,
22976
+ message: `Malformed operator '${pair_key}'. Did you mean '${malformed_suggestion}'?`,
22631
22977
  default_severity: import_node2.DiagnosticSeverity.Warning,
22632
- code: 6001 /* MALFORMED_OPERATOR */
22978
+ code: "MALFORMED_OPERATOR" /* MALFORMED_OPERATOR */
22633
22979
  };
22634
22980
  }
22635
22981
  if (CSTYLE_LOGICAL_PAIRS.has(pair_key)) {
@@ -22643,7 +22989,7 @@ class OperatorSequenceAnalyzer {
22643
22989
  pair_key,
22644
22990
  message,
22645
22991
  default_severity: import_node2.DiagnosticSeverity.Information,
22646
- code: 6003 /* CSTYLE_LOGICAL_IN_CONTROL_FLOW */
22992
+ code: "CSTYLE_LOGICAL_IN_CONTROL_FLOW" /* CSTYLE_LOGICAL_IN_CONTROL_FLOW */
22647
22993
  };
22648
22994
  } else {
22649
22995
  const special_message = CSTYLE_QUALIFIER_MESSAGES.get(pair_key);
@@ -22655,7 +23001,7 @@ class OperatorSequenceAnalyzer {
22655
23001
  pair_key,
22656
23002
  message,
22657
23003
  default_severity: import_node2.DiagnosticSeverity.Error,
22658
- code: 6002 /* INVALID_OPERATOR_SEQUENCE */
23004
+ code: "INVALID_OPERATOR_SEQUENCE" /* INVALID_OPERATOR_SEQUENCE */
22659
23005
  };
22660
23006
  }
22661
23007
  }
@@ -22669,7 +23015,7 @@ class OperatorSequenceAnalyzer {
22669
23015
  pair_key,
22670
23016
  message,
22671
23017
  default_severity: import_node2.DiagnosticSeverity.Error,
22672
- code: 6002 /* INVALID_OPERATOR_SEQUENCE */
23018
+ code: "INVALID_OPERATOR_SEQUENCE" /* INVALID_OPERATOR_SEQUENCE */
22673
23019
  };
22674
23020
  }
22675
23021
  if (this.is_allowed_adjacency(first_value, second_value)) {
@@ -22789,15 +23135,18 @@ class OperatorSequenceAnalyzer {
22789
23135
  }
22790
23136
  }
22791
23137
  }
22792
- var import_node2, SUGGESTIBLE_PAIRS, INVALID_PAIRS, CSTYLE_LOGICAL_PAIRS, SPECIAL_MESSAGES, CSTYLE_QUALIFIER_MESSAGES, CSTYLE_CONTROL_FLOW_MESSAGES, ARITHMETIC_OPS, COMPARISON_OPS, NEGATION_OPS, TRIVIA_TYPES, ADJACENCY_BREAKERS;
23138
+ var import_node2, SPACED_COMPOUND_PAIRS, MALFORMED_OPERATOR_PAIRS, INVALID_PAIRS, CSTYLE_LOGICAL_PAIRS, SPECIAL_MESSAGES, CSTYLE_QUALIFIER_MESSAGES, CSTYLE_CONTROL_FLOW_MESSAGES, ARITHMETIC_OPS, COMPARISON_OPS, NEGATION_OPS, TRIVIA_TYPES, ADJACENCY_BREAKERS;
22793
23139
  var init_operator_sequence_diagnostics = __esm(() => {
22794
23140
  init_types();
23141
+ init_diagnostic_code_description();
22795
23142
  import_node2 = __toESM(require_main4(), 1);
22796
- SUGGESTIBLE_PAIRS = new Map([
23143
+ SPACED_COMPOUND_PAIRS = new Map([
22797
23144
  ["< =", "<="],
22798
23145
  ["> =", ">="],
22799
23146
  ["! =", "!="],
22800
- ["~ =", "~="],
23147
+ ["~ =", "~="]
23148
+ ]);
23149
+ MALFORMED_OPERATOR_PAIRS = new Map([
22801
23150
  ["= =", "=="]
22802
23151
  ]);
22803
23152
  INVALID_PAIRS = new Set([
@@ -23002,7 +23351,8 @@ class MixedLogicalOperatorAnalyzer {
23002
23351
  message: "Mixed '&' and '|' without parentheses. " + "Use parentheses to clarify precedence " + "(e.g., '(x & y) | z' or 'x & (y | z)')",
23003
23352
  severity: my_severity,
23004
23353
  source: "sight",
23005
- code: 6004 /* MIXED_LOGICAL_OPERATORS */
23354
+ code: "MIXED_LOGICAL_OPERATORS" /* MIXED_LOGICAL_OPERATORS */,
23355
+ ...diagnostic_code_description_fields("MIXED_LOGICAL_OPERATORS" /* MIXED_LOGICAL_OPERATORS */)
23006
23356
  });
23007
23357
  }
23008
23358
  }
@@ -23022,6 +23372,7 @@ class MixedLogicalOperatorAnalyzer {
23022
23372
  var import_node3, LOGICAL_OPS, QUALIFIER_BREAKERS, EXPRESSION_BREAKERS;
23023
23373
  var init_mixed_logical_diagnostics = __esm(() => {
23024
23374
  init_types();
23375
+ init_diagnostic_code_description();
23025
23376
  import_node3 = __toESM(require_main4(), 1);
23026
23377
  LOGICAL_OPS = new Set(["&", "|"]);
23027
23378
  QUALIFIER_BREAKERS = new Set(["if", "in"]);
@@ -23035,6 +23386,15 @@ var init_mixed_logical_diagnostics = __esm(() => {
23035
23386
 
23036
23387
  // src/providers/diagnostics.ts
23037
23388
  import { createHash } from "crypto";
23389
+ function is_lexer_error_code(code) {
23390
+ return typeof code === "string" && LEXER_ERROR_CODES.has(code);
23391
+ }
23392
+ function is_parser_error_code(code) {
23393
+ return typeof code === "string" && PARSER_ERROR_CODES.has(code);
23394
+ }
23395
+ function is_stata_diagnostic_code(code) {
23396
+ return typeof code === "string" && STATA_DIAGNOSTIC_CODES.has(code);
23397
+ }
23038
23398
 
23039
23399
  class DiagnosticsProvider {
23040
23400
  connection;
@@ -23121,17 +23481,17 @@ class DiagnosticsProvider {
23121
23481
  if (this.is_in_embedded_context(my_diagnostic.range.start, the_context_ranges)) {
23122
23482
  continue;
23123
23483
  }
23124
- if (defer_undefined_diagnostics && (my_diagnostic.code === 2001 /* UNDEFINED_MACRO */ || my_diagnostic.code === 2002 /* UNDEFINED_VARIABLE */)) {
23484
+ if (defer_undefined_diagnostics && (my_diagnostic.code === "UNDEFINED_MACRO" /* UNDEFINED_MACRO */ || my_diagnostic.code === "UNDEFINED_VARIABLE" /* UNDEFINED_VARIABLE */)) {
23125
23485
  continue;
23126
23486
  }
23127
- const is_undefined_symbol = my_diagnostic.code === 2001 /* UNDEFINED_MACRO */ || my_diagnostic.code === 2002 /* UNDEFINED_VARIABLE */;
23487
+ const is_undefined_symbol = my_diagnostic.code === "UNDEFINED_MACRO" /* UNDEFINED_MACRO */ || my_diagnostic.code === "UNDEFINED_VARIABLE" /* UNDEFINED_VARIABLE */;
23128
23488
  const symbol_name = is_undefined_symbol ? this.extract_symbol_name_from_diagnostic(my_diagnostic) : null;
23129
23489
  const reference_kind = is_undefined_symbol ? this.classify_reference_kind(my_diagnostic) : null;
23130
23490
  if (resolved_scope && symbol_name) {
23131
23491
  if (this.is_symbol_defined_in_scope(symbol_name, resolved_scope.symbols, my_diagnostic.code, document.uri, reference_kind)) {
23132
23492
  continue;
23133
23493
  }
23134
- if (my_diagnostic.code === 2001 /* UNDEFINED_MACRO */ && this.is_c_local_from_resolved_program(symbol_name, resolved_scope.symbols, document, my_diagnostic.range.start.line)) {
23494
+ if (my_diagnostic.code === "UNDEFINED_MACRO" /* UNDEFINED_MACRO */ && this.is_c_local_from_resolved_program(symbol_name, resolved_scope.symbols, document, my_diagnostic.range.start.line)) {
23135
23495
  continue;
23136
23496
  }
23137
23497
  }
@@ -23250,15 +23610,12 @@ class DiagnosticsProvider {
23250
23610
  extract_lexer_errors(document) {
23251
23611
  const lexer_errors = [];
23252
23612
  for (const diag of document.diagnostics) {
23253
- if (diag.code && typeof diag.code === "number") {
23254
- const code = diag.code;
23255
- if (code >= 1001 && code <= 1004) {
23256
- lexer_errors.push({
23257
- message: diag.message,
23258
- range: diag.range,
23259
- code
23260
- });
23261
- }
23613
+ if (is_lexer_error_code(diag.code)) {
23614
+ lexer_errors.push({
23615
+ message: diag.message,
23616
+ range: diag.range,
23617
+ code: diag.code
23618
+ });
23262
23619
  }
23263
23620
  }
23264
23621
  return lexer_errors;
@@ -23266,15 +23623,12 @@ class DiagnosticsProvider {
23266
23623
  extract_parser_errors(document) {
23267
23624
  const parser_errors = [];
23268
23625
  for (const diag of document.diagnostics) {
23269
- if (diag.code && typeof diag.code === "number") {
23270
- const code = diag.code;
23271
- if (code >= 3000 && code <= 3014) {
23272
- parser_errors.push({
23273
- message: diag.message,
23274
- range: diag.range,
23275
- code
23276
- });
23277
- }
23626
+ if (is_parser_error_code(diag.code)) {
23627
+ parser_errors.push({
23628
+ message: diag.message,
23629
+ range: diag.range,
23630
+ code: diag.code
23631
+ });
23278
23632
  }
23279
23633
  }
23280
23634
  return parser_errors;
@@ -23282,25 +23636,26 @@ class DiagnosticsProvider {
23282
23636
  extract_semantic_diagnostics(document) {
23283
23637
  const semantic_diags = [];
23284
23638
  for (const diag of document.diagnostics) {
23285
- if (diag.code && typeof diag.code === "number") {
23286
- const code = diag.code;
23287
- if (code === 2001 /* UNDEFINED_MACRO */ || code === 2002 /* UNDEFINED_VARIABLE */ || code === 2004 /* MISSING_VARIABLE_NAME */) {
23288
- const severity_map = {
23289
- [import_vscode_languageserver2.DiagnosticSeverity.Error]: "error",
23290
- [import_vscode_languageserver2.DiagnosticSeverity.Warning]: "warning",
23291
- [import_vscode_languageserver2.DiagnosticSeverity.Information]: "information",
23292
- [import_vscode_languageserver2.DiagnosticSeverity.Hint]: "hint"
23293
- };
23294
- const data = diag.data;
23295
- semantic_diags.push({
23296
- message: diag.message,
23297
- range: diag.range,
23298
- code,
23299
- severity: severity_map[diag.severity ?? import_vscode_languageserver2.DiagnosticSeverity.Error],
23300
- symbol_name: data?.symbol_name,
23301
- reference_kind: data?.reference_kind
23302
- });
23303
- }
23639
+ if (!is_stata_diagnostic_code(diag.code)) {
23640
+ continue;
23641
+ }
23642
+ const code = diag.code;
23643
+ if (code === "UNDEFINED_MACRO" /* UNDEFINED_MACRO */ || code === "UNDEFINED_VARIABLE" /* UNDEFINED_VARIABLE */ || code === "INVALID_MACRO_CHAR" /* INVALID_MACRO_CHAR */ || code === "MISSING_VARIABLE_NAME" /* MISSING_VARIABLE_NAME */) {
23644
+ const severity_map = {
23645
+ [import_vscode_languageserver2.DiagnosticSeverity.Error]: "error",
23646
+ [import_vscode_languageserver2.DiagnosticSeverity.Warning]: "warning",
23647
+ [import_vscode_languageserver2.DiagnosticSeverity.Information]: "information",
23648
+ [import_vscode_languageserver2.DiagnosticSeverity.Hint]: "hint"
23649
+ };
23650
+ const data = diag.data;
23651
+ semantic_diags.push({
23652
+ message: diag.message,
23653
+ range: diag.range,
23654
+ code,
23655
+ severity: severity_map[diag.severity ?? import_vscode_languageserver2.DiagnosticSeverity.Error],
23656
+ symbol_name: data?.symbol_name,
23657
+ reference_kind: data?.reference_kind
23658
+ });
23304
23659
  }
23305
23660
  }
23306
23661
  return semantic_diags;
@@ -23322,15 +23677,15 @@ class DiagnosticsProvider {
23322
23677
  convert_lexer_error(error, config) {
23323
23678
  let severity;
23324
23679
  switch (error.code) {
23325
- case 1001 /* UNBALANCED_QUOTES */:
23326
- case 1002 /* UNBALANCED_BLOCK_COMMENT */:
23327
- case 1003 /* UNTERMINATED_STATEMENT */:
23680
+ case "UNBALANCED_QUOTES" /* UNBALANCED_QUOTES */:
23681
+ case "UNBALANCED_BLOCK_COMMENT" /* UNBALANCED_BLOCK_COMMENT */:
23682
+ case "UNTERMINATED_STATEMENT" /* UNTERMINATED_STATEMENT */:
23328
23683
  severity = import_vscode_languageserver2.DiagnosticSeverity.Error;
23329
23684
  break;
23330
- case 1004 /* CONTINUATION_NO_SPACE */:
23685
+ case "CONTINUATION_NO_SPACE" /* CONTINUATION_NO_SPACE */:
23331
23686
  severity = this.get_severity_from_config(config.diagnostics.severity.styleWarnings);
23332
23687
  break;
23333
- case 1005 /* BLOCK_COMMENT_IN_STAR_COMMENT */:
23688
+ case "BLOCK_COMMENT_IN_STAR_COMMENT" /* BLOCK_COMMENT_IN_STAR_COMMENT */:
23334
23689
  severity = import_vscode_languageserver2.DiagnosticSeverity.Warning;
23335
23690
  break;
23336
23691
  default:
@@ -23344,21 +23699,22 @@ class DiagnosticsProvider {
23344
23699
  message: error.message,
23345
23700
  severity,
23346
23701
  code: error.code,
23347
- source: "sight"
23702
+ source: "sight",
23703
+ ...diagnostic_code_description_fields(error.code)
23348
23704
  };
23349
23705
  }
23350
23706
  get_undefined_symbol_severity_setting(diagnostic_code, config) {
23351
- if (diagnostic_code === 2001 /* UNDEFINED_MACRO */) {
23707
+ if (diagnostic_code === "UNDEFINED_MACRO" /* UNDEFINED_MACRO */) {
23352
23708
  return config.diagnostics.severity.undefinedMacro;
23353
23709
  }
23354
- if (diagnostic_code === 2002 /* UNDEFINED_VARIABLE */) {
23710
+ if (diagnostic_code === "UNDEFINED_VARIABLE" /* UNDEFINED_VARIABLE */) {
23355
23711
  return config.diagnostics.severity.undefinedVariable;
23356
23712
  }
23357
23713
  return null;
23358
23714
  }
23359
23715
  convert_parser_error(error, _config) {
23360
23716
  let severity = import_vscode_languageserver2.DiagnosticSeverity.Error;
23361
- if (error.code === 3006 /* CODE_AFTER_OPEN_BRACE */ || error.code === 3009 /* REDUNDANT_MACRO_SUFFIX */) {
23717
+ if (error.code === "CODE_AFTER_OPEN_BRACE" /* CODE_AFTER_OPEN_BRACE */ || error.code === "REDUNDANT_MACRO_SUFFIX" /* REDUNDANT_MACRO_SUFFIX */) {
23362
23718
  severity = import_vscode_languageserver2.DiagnosticSeverity.Warning;
23363
23719
  }
23364
23720
  return {
@@ -23366,38 +23722,42 @@ class DiagnosticsProvider {
23366
23722
  message: error.message,
23367
23723
  severity,
23368
23724
  code: error.code,
23369
- source: "sight"
23725
+ source: "sight",
23726
+ ...diagnostic_code_description_fields(error.code)
23370
23727
  };
23371
23728
  }
23372
23729
  should_suppress_undefined_symbol(document, diagnostic_range) {
23373
23730
  const diagnostic_line = diagnostic_range.start.line;
23374
- const line_count = get_line_count(document);
23375
- if (diagnostic_line < line_count) {
23376
- const current_line = get_line_text(document, diagnostic_line);
23377
- if (current_line.includes("// @lsp-ignore")) {
23378
- return true;
23379
- }
23731
+ if (document.ignored_lines?.has(diagnostic_line)) {
23732
+ return true;
23733
+ }
23734
+ if (document.tokens && document.tokens.length > 0) {
23735
+ return false;
23736
+ }
23737
+ const current_line = get_line_text(document, diagnostic_line);
23738
+ if (has_trailing_ignore_directive(current_line)) {
23739
+ return true;
23380
23740
  }
23381
23741
  if (diagnostic_line > 0) {
23382
23742
  const previous_line = get_line_text(document, diagnostic_line - 1);
23383
- if (previous_line.includes("// @lsp-ignore-next")) {
23743
+ if (has_ignore_directive(previous_line) || has_ignore_next_directive(previous_line)) {
23384
23744
  return true;
23385
23745
  }
23386
23746
  }
23387
23747
  return false;
23388
23748
  }
23389
23749
  convert_semantic_diagnostic(diagnostic, config, document) {
23390
- if (document && (diagnostic.code === 2001 /* UNDEFINED_MACRO */ || diagnostic.code === 2002 /* UNDEFINED_VARIABLE */ || diagnostic.code === 2003 /* OUT_OF_SCOPE_SYMBOL */)) {
23750
+ if (document && (diagnostic.code === "UNDEFINED_MACRO" /* UNDEFINED_MACRO */ || diagnostic.code === "UNDEFINED_VARIABLE" /* UNDEFINED_VARIABLE */ || diagnostic.code === "OUT_OF_SCOPE_SYMBOL" /* OUT_OF_SCOPE_SYMBOL */)) {
23391
23751
  if (this.should_suppress_undefined_symbol(document, diagnostic.range)) {
23392
23752
  return null;
23393
23753
  }
23394
23754
  }
23395
23755
  let severity;
23396
23756
  switch (diagnostic.code) {
23397
- case 2001 /* UNDEFINED_MACRO */:
23398
- case 2002 /* UNDEFINED_VARIABLE */:
23399
- case 2003 /* OUT_OF_SCOPE_SYMBOL */: {
23400
- const severity_setting = this.get_undefined_symbol_severity_setting(diagnostic.code === 2003 /* OUT_OF_SCOPE_SYMBOL */ ? diagnostic.base_code : diagnostic.code, config);
23757
+ case "UNDEFINED_MACRO" /* UNDEFINED_MACRO */:
23758
+ case "UNDEFINED_VARIABLE" /* UNDEFINED_VARIABLE */:
23759
+ case "OUT_OF_SCOPE_SYMBOL" /* OUT_OF_SCOPE_SYMBOL */: {
23760
+ const severity_setting = this.get_undefined_symbol_severity_setting(diagnostic.code === "OUT_OF_SCOPE_SYMBOL" /* OUT_OF_SCOPE_SYMBOL */ ? diagnostic.base_code : diagnostic.code, config);
23401
23761
  if (!severity_setting) {
23402
23762
  severity = this.semantic_severity_to_lsp(diagnostic.severity);
23403
23763
  break;
@@ -23417,6 +23777,7 @@ class DiagnosticsProvider {
23417
23777
  severity,
23418
23778
  code: diagnostic.code,
23419
23779
  source: "sight",
23780
+ ...diagnostic_code_description_fields(diagnostic.code),
23420
23781
  ...undefined_symbol_data_fields(diagnostic)
23421
23782
  };
23422
23783
  }
@@ -23424,7 +23785,7 @@ class DiagnosticsProvider {
23424
23785
  return this.convert_semantic_diagnostic({
23425
23786
  message: format_out_of_scope_message(symbol_name, match.symbol_kind, match.reason),
23426
23787
  range: base_diagnostic.range,
23427
- code: 2003 /* OUT_OF_SCOPE_SYMBOL */,
23788
+ code: "OUT_OF_SCOPE_SYMBOL" /* OUT_OF_SCOPE_SYMBOL */,
23428
23789
  severity: base_diagnostic.severity,
23429
23790
  base_code: base_diagnostic.code
23430
23791
  }, config, document);
@@ -23523,15 +23884,7 @@ class DiagnosticsProvider {
23523
23884
  return false;
23524
23885
  }
23525
23886
  is_stata_specific_error(error_code) {
23526
- const structural_errors = [
23527
- 1001 /* UNBALANCED_QUOTES */,
23528
- 1002 /* UNBALANCED_BLOCK_COMMENT */
23529
- ];
23530
- if (typeof error_code === "number") {
23531
- return !structural_errors.includes(error_code);
23532
- }
23533
- const error_code_str = String(error_code).toLowerCase();
23534
- return !(error_code_str.includes("quote") || error_code_str.includes("comment") || error_code_str.includes("brace"));
23887
+ return !STRUCTURAL_EMBEDDED_ERROR_CODES.has(error_code);
23535
23888
  }
23536
23889
  convert_context_diagnostic(diagnostic) {
23537
23890
  const severity_map = {
@@ -23544,7 +23897,8 @@ class DiagnosticsProvider {
23544
23897
  message: diagnostic.message,
23545
23898
  severity: severity_map[diagnostic.severity],
23546
23899
  code: diagnostic.code,
23547
- source: "sight"
23900
+ source: "sight",
23901
+ ...diagnostic_code_description_fields(diagnostic.code)
23548
23902
  };
23549
23903
  }
23550
23904
  convert_directive_diagnostic(diagnostic, config) {
@@ -23566,7 +23920,8 @@ class DiagnosticsProvider {
23566
23920
  message: diagnostic.message,
23567
23921
  severity: severity2,
23568
23922
  code: diagnostic.code,
23569
- source: "sight"
23923
+ source: "sight",
23924
+ ...diagnostic_code_description_fields(diagnostic.code)
23570
23925
  };
23571
23926
  }
23572
23927
  if (diagnostic.kind === "truncation") {
@@ -23575,7 +23930,8 @@ class DiagnosticsProvider {
23575
23930
  message: diagnostic.message,
23576
23931
  severity: this.semantic_severity_to_lsp(diagnostic.severity),
23577
23932
  code: diagnostic.code,
23578
- source: "sight"
23933
+ source: "sight",
23934
+ ...diagnostic_code_description_fields(diagnostic.code)
23579
23935
  };
23580
23936
  }
23581
23937
  const is_missing_file = diagnostic.kind === "missing_file" || diagnostic.message.includes("Cannot read file");
@@ -23588,7 +23944,9 @@ class DiagnosticsProvider {
23588
23944
  range: diagnostic.range,
23589
23945
  message: diagnostic.message,
23590
23946
  severity,
23591
- source: "sight"
23947
+ code: diagnostic.code,
23948
+ source: "sight",
23949
+ ...diagnostic_code_description_fields(diagnostic.code)
23592
23950
  };
23593
23951
  }
23594
23952
  extract_symbol_name_from_diagnostic(diagnostic) {
@@ -23598,7 +23956,7 @@ class DiagnosticsProvider {
23598
23956
  const is_external_symbol = (symbol) => {
23599
23957
  return !!symbol?.sourceUri && symbol.sourceUri !== current_document_uri;
23600
23958
  };
23601
- if (diagnostic_code === 2001 /* UNDEFINED_MACRO */) {
23959
+ if (diagnostic_code === "UNDEFINED_MACRO" /* UNDEFINED_MACRO */) {
23602
23960
  if (reference_kind === "local") {
23603
23961
  return is_external_symbol(symbols.localMacros.get(symbol_name));
23604
23962
  }
@@ -23607,7 +23965,7 @@ class DiagnosticsProvider {
23607
23965
  }
23608
23966
  return false;
23609
23967
  }
23610
- if (diagnostic_code === 2002 /* UNDEFINED_VARIABLE */) {
23968
+ if (diagnostic_code === "UNDEFINED_VARIABLE" /* UNDEFINED_VARIABLE */) {
23611
23969
  if (reference_kind !== "variable") {
23612
23970
  return false;
23613
23971
  }
@@ -23622,7 +23980,7 @@ class DiagnosticsProvider {
23622
23980
  }
23623
23981
  return symbol.sourceUri === current_document_uri || symbol.location?.uri === current_document_uri;
23624
23982
  };
23625
- if (diagnostic_code === 2001 /* UNDEFINED_MACRO */) {
23983
+ if (diagnostic_code === "UNDEFINED_MACRO" /* UNDEFINED_MACRO */) {
23626
23984
  if (reference_kind === "local") {
23627
23985
  return is_from_current_document(symbols.localMacros.get(symbol_name));
23628
23986
  }
@@ -23631,13 +23989,13 @@ class DiagnosticsProvider {
23631
23989
  }
23632
23990
  return is_from_current_document(symbols.localMacros.get(symbol_name)) || is_from_current_document(symbols.globalMacros.get(symbol_name));
23633
23991
  }
23634
- if (diagnostic_code === 2002 /* UNDEFINED_VARIABLE */) {
23992
+ if (diagnostic_code === "UNDEFINED_VARIABLE" /* UNDEFINED_VARIABLE */) {
23635
23993
  return is_from_current_document(symbols.variables.get(symbol_name)) || is_from_current_document(symbols.scalars?.get(symbol_name)) || is_from_current_document(symbols.matrices?.get(symbol_name));
23636
23994
  }
23637
23995
  return false;
23638
23996
  }
23639
23997
  is_symbol_excluded_by_forward_call(symbol_name, call_site, diagnostic_code, reference_kind, current_document_uri) {
23640
- if (diagnostic_code !== 2001 /* UNDEFINED_MACRO */) {
23998
+ if (diagnostic_code !== "UNDEFINED_MACRO" /* UNDEFINED_MACRO */) {
23641
23999
  return false;
23642
24000
  }
23643
24001
  if (reference_kind !== "local") {
@@ -23653,7 +24011,7 @@ class DiagnosticsProvider {
23653
24011
  const is_external_symbol = (symbol) => {
23654
24012
  return !!symbol?.sourceUri && symbol.sourceUri !== current_document_uri;
23655
24013
  };
23656
- if (diagnostic_code === 2001 /* UNDEFINED_MACRO */) {
24014
+ if (diagnostic_code === "UNDEFINED_MACRO" /* UNDEFINED_MACRO */) {
23657
24015
  if (reference_kind === "local") {
23658
24016
  return effective_type === "include" && is_external_symbol(symbols.localMacros.get(symbol_name));
23659
24017
  }
@@ -23662,7 +24020,7 @@ class DiagnosticsProvider {
23662
24020
  }
23663
24021
  return false;
23664
24022
  }
23665
- if (diagnostic_code === 2002 /* UNDEFINED_VARIABLE */) {
24023
+ if (diagnostic_code === "UNDEFINED_VARIABLE" /* UNDEFINED_VARIABLE */) {
23666
24024
  if (reference_kind !== "variable") {
23667
24025
  return false;
23668
24026
  }
@@ -23731,16 +24089,25 @@ class DiagnosticsProvider {
23731
24089
  return reference_kind === out_of_scope_type;
23732
24090
  }
23733
24091
  }
23734
- var import_vscode_languageserver2, host_probe;
24092
+ var import_vscode_languageserver2, LEXER_ERROR_CODES, PARSER_ERROR_CODES, STATA_DIAGNOSTIC_CODES, STRUCTURAL_EMBEDDED_ERROR_CODES, host_probe;
23735
24093
  var init_diagnostics = __esm(() => {
23736
24094
  init_types2();
23737
24095
  init_types();
23738
24096
  init_scope_resolver();
24097
+ init_diagnostic_code_description();
23739
24098
  init_file_path_utils();
24099
+ init_directives();
23740
24100
  init_indentation_diagnostics();
23741
24101
  init_operator_sequence_diagnostics();
23742
24102
  init_mixed_logical_diagnostics();
23743
24103
  import_vscode_languageserver2 = __toESM(require_main4(), 1);
24104
+ LEXER_ERROR_CODES = new Set(Object.values(LexerErrorCode));
24105
+ PARSER_ERROR_CODES = new Set(Object.values(ParseErrorCode));
24106
+ STATA_DIAGNOSTIC_CODES = new Set(Object.values(StataDiagnosticCode));
24107
+ STRUCTURAL_EMBEDDED_ERROR_CODES = new Set([
24108
+ "UNBALANCED_QUOTES" /* UNBALANCED_QUOTES */,
24109
+ "UNBALANCED_BLOCK_COMMENT" /* UNBALANCED_BLOCK_COMMENT */
24110
+ ]);
23744
24111
  host_probe = host_is_case_sensitive;
23745
24112
  });
23746
24113
 
@@ -24656,6 +25023,28 @@ function is_cursor_in_comment_from_tokens(tokens, position) {
24656
25023
  }
24657
25024
  return false;
24658
25025
  }
25026
+ function is_cursor_in_block_comment(document, position, options) {
25027
+ if (document.tokens && document.tokens.length > 0) {
25028
+ const the_candidates = document.token_line_index?.size ? document.token_line_index.get(position.line) ?? [] : document.tokens;
25029
+ for (const my_token of the_candidates) {
25030
+ const is_block = my_token.type === "COMMENT_BLOCK";
25031
+ const is_spanned_line = my_token.type === "COMMENT_LINE" && my_token.range.end.line > my_token.range.start.line;
25032
+ if (is_block || is_spanned_line) {
25033
+ if (is_position_in_range(position, my_token.range)) {
25034
+ return true;
25035
+ }
25036
+ if (!my_token.value.endsWith("*/") && position.line === my_token.range.end.line && position.character === my_token.range.end.character) {
25037
+ return true;
25038
+ }
25039
+ }
25040
+ }
25041
+ return false;
25042
+ }
25043
+ if (options?.require_tokens) {
25044
+ return false;
25045
+ }
25046
+ return is_in_block_comment(document.content, position);
25047
+ }
24659
25048
  function is_cursor_in_comment_heuristic(content, position) {
24660
25049
  const doc = { content, line_offsets: compute_line_offsets(content) };
24661
25050
  const current_line = get_line_text(doc, position.line);
@@ -24936,7 +25325,7 @@ function detect_completion_context(document, position, tokens, command_db) {
24936
25325
  return extended_macro_context;
24937
25326
  }
24938
25327
  const directive_context = detect_directive_context(text_before_cursor);
24939
- if (directive_context) {
25328
+ if (directive_context && !is_cursor_in_block_comment(document, position)) {
24940
25329
  return directive_context;
24941
25330
  }
24942
25331
  const command_path_context = detect_command_path_context(text_before_cursor);
@@ -25084,8 +25473,7 @@ function detect_directive_context(text_before_cursor) {
25084
25473
  return null;
25085
25474
  }
25086
25475
  const comment_content = comment_match[2];
25087
- const directive_pattern = /(@lsp-[a-zA-Z-]+)\s*:\s*(.*)$/;
25088
- const directive_match = comment_content.match(directive_pattern);
25476
+ const directive_match = comment_content.match(DIRECTIVE_PATH_CONTEXT_PATTERN);
25089
25477
  if (directive_match) {
25090
25478
  const directive = directive_match[1];
25091
25479
  const path_part = directive_match[2];
@@ -25360,6 +25748,9 @@ class CompletionProvider {
25360
25748
  this.context_tracker = document.context_tracker;
25361
25749
  }
25362
25750
  const my_current_context = this.context_tracker ? this.context_tracker.get_context_at_position(position) : "stata" /* STATA */;
25751
+ if (my_current_context === "stata" /* STATA */ && is_cursor_in_block_comment(document, position, { require_tokens: true })) {
25752
+ return [];
25753
+ }
25363
25754
  const context = detect_completion_context(document, position, undefined, this.command_db);
25364
25755
  if (my_current_context !== "stata" /* STATA */ && context.type !== "macro") {
25365
25756
  const my_boundary_completions = this.get_block_boundary_completions(document, position);
@@ -26682,7 +27073,7 @@ class CompletionProvider {
26682
27073
  return true;
26683
27074
  }
26684
27075
  }
26685
- var import_vscode_languageserver4;
27076
+ var import_vscode_languageserver4, DIRECTIVE_PATH_CONTEXT_PATTERN;
26686
27077
  var init_completion = __esm(() => {
26687
27078
  init_command_database();
26688
27079
  init_types2();
@@ -26690,9 +27081,12 @@ var init_completion = __esm(() => {
26690
27081
  init_scope_resolver();
26691
27082
  init_analyzer();
26692
27083
  init_file_path_utils();
27084
+ init_directives();
27085
+ init_comment_utils();
26693
27086
  init_logger();
26694
27087
  init_macro_completion();
26695
27088
  import_vscode_languageserver4 = __toESM(require_main4(), 1);
27089
+ DIRECTIVE_PATH_CONTEXT_PATTERN = new RegExp(`^\\s*(${DIRECTIVE_BODY_PREFIX_PATTERN}[a-zA-Z-]+)\\s*:?\\s*(.*)$`);
26696
27090
  });
26697
27091
 
26698
27092
  // src/utils/marker-scanner.ts
@@ -27327,6 +27721,7 @@ var init_server_handlers = __esm(() => {
27327
27721
  undefinedVariable: "off",
27328
27722
  styleWarnings: "hint",
27329
27723
  malformedOperator: "warning",
27724
+ spacedCompoundOperator: "information",
27330
27725
  invalidOperatorSequence: "error",
27331
27726
  cStyleLogicalInControlFlow: "information",
27332
27727
  mixedLogicalOperators: "warning"
@@ -27460,6 +27855,9 @@ function validate_comment_formatting_config(config, log_warning) {
27460
27855
  if (diagnostics.severity.malformedOperator && valid_severities.includes(diagnostics.severity.malformedOperator)) {
27461
27856
  validated_config.diagnostics.severity.malformedOperator = diagnostics.severity.malformedOperator;
27462
27857
  }
27858
+ if (diagnostics.severity.spacedCompoundOperator && valid_severities.includes(diagnostics.severity.spacedCompoundOperator)) {
27859
+ validated_config.diagnostics.severity.spacedCompoundOperator = diagnostics.severity.spacedCompoundOperator;
27860
+ }
27463
27861
  if (diagnostics.severity.invalidOperatorSequence && valid_severities.includes(diagnostics.severity.invalidOperatorSequence)) {
27464
27862
  validated_config.diagnostics.severity.invalidOperatorSequence = diagnostics.severity.invalidOperatorSequence;
27465
27863
  }
@@ -27626,7 +28024,7 @@ function diagnostic_exceeds_threshold(diagnostic, max_severity) {
27626
28024
  return severity_level(diagnostic) > max_severity;
27627
28025
  }
27628
28026
  function is_truncation_diagnostic(diagnostic) {
27629
- return diagnostic.code === 7002 /* CROSS_FILE_TRUNCATED */;
28027
+ return diagnostic.code === "CROSS_FILE_TRUNCATED" /* CROSS_FILE_TRUNCATED */;
27630
28028
  }
27631
28029
  function env_flag_is_set(value) {
27632
28030
  return value !== undefined && value.length > 0;
@@ -27657,9 +28055,14 @@ function code_text(code) {
27657
28055
  return code;
27658
28056
  return "";
27659
28057
  }
28058
+ function text_code_text(code) {
28059
+ if (typeof code === "string")
28060
+ return code.toLowerCase();
28061
+ return code_text(code);
28062
+ }
27660
28063
  function sarif_rule_id(code) {
27661
28064
  const value = code_text(code);
27662
- return /^\d+$/.test(value) ? `SIGHT${value}` : value || "SIGHT";
28065
+ return value || "SIGHT";
27663
28066
  }
27664
28067
  function severity_word(diagnostic) {
27665
28068
  switch (diagnostic.severity) {
@@ -27720,7 +28123,7 @@ function render_text(records, options) {
27720
28123
  if (is_truncation_diagnostic(record.diagnostic)) {
27721
28124
  truncation_count++;
27722
28125
  }
27723
- const code = code_text(record.diagnostic.code);
28126
+ const code = text_code_text(record.diagnostic.code);
27724
28127
  const code_suffix = code ? ` [${code}]` : "";
27725
28128
  lines.push(`${record.relative_path}:` + `${record.diagnostic.range.start.line + 1}:` + `${record.diagnostic.range.start.character + 1} ` + `${colorize(word, options.use_color)}: ` + `${record.diagnostic.message}${code_suffix}`);
27726
28129
  }
@@ -27756,11 +28159,15 @@ function render_sarif(records, version) {
27756
28159
  driver: {
27757
28160
  name: "sight",
27758
28161
  version,
27759
- rules: rule_ids.map((id) => ({
27760
- id,
27761
- name: id,
27762
- shortDescription: { text: id }
27763
- }))
28162
+ rules: rule_ids.map((id) => {
28163
+ const description = id === "SIGHT" ? undefined : diagnostic_code_description(id);
28164
+ return {
28165
+ id,
28166
+ name: id,
28167
+ shortDescription: { text: id },
28168
+ ...description ? { helpUri: description.href } : {}
28169
+ };
28170
+ })
27764
28171
  }
27765
28172
  },
27766
28173
  results: sorted.map((record) => ({
@@ -27786,6 +28193,7 @@ function render_sarif(records, version) {
27786
28193
  var import_vscode_languageserver5, EXIT_OK = 0, EXIT_CHECK_FAILED = 1, EXIT_OPERATOR_ERROR = 2, FORCE_COLOR_DISABLED_VALUES;
27787
28194
  var init_shared = __esm(() => {
27788
28195
  init_types();
28196
+ init_diagnostic_code_description();
27789
28197
  import_vscode_languageserver5 = __toESM(require_main4(), 1);
27790
28198
  FORCE_COLOR_DISABLED_VALUES = new Set(["0", "false", "off"]);
27791
28199
  });
@@ -27884,7 +28292,8 @@ function file_level_diagnostic(code, message) {
27884
28292
  severity: import_vscode_languageserver6.DiagnosticSeverity.Error,
27885
28293
  source: "sight",
27886
28294
  code,
27887
- message
28295
+ message,
28296
+ ...diagnostic_code_description_fields(code)
27888
28297
  };
27889
28298
  }
27890
28299
  function size_limit_diagnostic(actual_bytes, limit_bytes) {
@@ -27972,6 +28381,7 @@ function read_source_file(file_path) {
27972
28381
  var import_vscode_languageserver6;
27973
28382
  var init_source_files = __esm(() => {
27974
28383
  init_file_path_utils();
28384
+ init_diagnostic_code_description();
27975
28385
  init_shared();
27976
28386
  import_vscode_languageserver6 = __toESM(require_main4(), 1);
27977
28387
  });
@@ -30458,15 +30868,17 @@ class DefinitionProvider {
30458
30868
  if (cancellation_token?.isCancellationRequested) {
30459
30869
  return null;
30460
30870
  }
30871
+ const my_context_tracker = context_tracker ?? document.context_tracker;
30872
+ const my_context = my_context_tracker ? my_context_tracker.get_context_at_position(position) : "stata" /* STATA */;
30873
+ if (my_context === "stata" /* STATA */ && is_cursor_in_block_comment(document, position, { require_tokens: true })) {
30874
+ return null;
30875
+ }
30461
30876
  const file_definition = this.get_include_definition(document, position);
30462
30877
  if (file_definition) {
30463
30878
  return file_definition;
30464
30879
  }
30465
- if (context_tracker) {
30466
- const my_context = context_tracker.get_context_at_position(position);
30467
- if (my_context !== "stata" /* STATA */) {
30468
- return await this.get_macro_definition_only(document, position, workspace_symbols, scope_resolver, workspace_indexer, cross_file_config, cancellation_token);
30469
- }
30880
+ if (my_context !== "stata" /* STATA */) {
30881
+ return await this.get_macro_definition_only(document, position, workspace_symbols, scope_resolver, workspace_indexer, cross_file_config, cancellation_token);
30470
30882
  }
30471
30883
  const word_info = this.get_word_at_position(document, position);
30472
30884
  if (!word_info) {
@@ -31106,22 +31518,18 @@ class DefinitionProvider {
31106
31518
  }
31107
31519
  }
31108
31520
  }
31109
- const directive_match = line_text.match(/@lsp-(done-by|included-by|do|run|include):?\s+(?:"([^"]+)"|([^\s]+))/);
31110
- if (directive_match) {
31521
+ const directive_match = line_text.match(PATH_BEARING_DIRECTIVE_PATTERN);
31522
+ if (directive_match && is_cursor_in_comment(document, position) && !is_cursor_in_block_comment(document, position)) {
31111
31523
  const quoted_path = directive_match[2];
31112
31524
  const unquoted_path = directive_match[3];
31113
31525
  const file_path = quoted_path || unquoted_path;
31114
31526
  const match_start = directive_match.index;
31115
- const DIRECTIVE_PREFIX = "@lsp-";
31116
- let cursor = match_start + DIRECTIVE_PREFIX.length + directive_match[1].length;
31117
- if (line_text[cursor] === ":")
31118
- cursor++;
31119
- while (cursor < line_text.length && /\s/.test(line_text[cursor])) {
31120
- cursor++;
31121
- }
31122
- if (quoted_path)
31123
- cursor++;
31124
- const path_start = cursor;
31527
+ const keyword_start = directive_match[0].indexOf(directive_match[1]);
31528
+ const path_literal = quoted_path ? `"${file_path}"` : file_path;
31529
+ const path_literal_start = directive_match[0].indexOf(path_literal, keyword_start + directive_match[1].length);
31530
+ if (path_literal_start < 0)
31531
+ return null;
31532
+ const path_start = match_start + path_literal_start + (quoted_path ? 1 : 0);
31125
31533
  const path_end = path_start + file_path.length;
31126
31534
  if (position.character >= path_start && position.character <= path_end) {
31127
31535
  const resolved_path = this.resolve_file_path(document.uri, file_path);
@@ -31160,12 +31568,15 @@ class DefinitionProvider {
31160
31568
  return null;
31161
31569
  }
31162
31570
  }
31571
+ var PATH_BEARING_DIRECTIVE_PATTERN;
31163
31572
  var init_definition = __esm(() => {
31164
31573
  init_types();
31165
31574
  init_scope_resolver();
31166
31575
  init_esm();
31167
31576
  init_file_path_utils();
31168
31577
  init_comment_utils();
31578
+ init_directives();
31579
+ PATH_BEARING_DIRECTIVE_PATTERN = new RegExp(`${DIRECTIVE_PREFIX_PATTERN}(${BACKWARD_DIRECTIVE_KEYWORDS}|${FORWARD_DIRECTIVE_KEYWORDS})` + String.raw`:?\s+(?:"([^"]+)"|([^\s]+))` + CALL_SITE_PARAMS_FRAGMENT + String.raw`\s*$`);
31169
31580
  });
31170
31581
 
31171
31582
  // src/providers/references.ts
@@ -33862,7 +34273,7 @@ function find_protected_regions(expression) {
33862
34273
  end: i,
33863
34274
  type: "nested_macro"
33864
34275
  });
33865
- }
34276
+ } else {}
33866
34277
  continue;
33867
34278
  }
33868
34279
  if (expression[i] === "$" && i + 1 < expression.length && expression[i + 1] === "{") {
@@ -66692,4 +67103,4 @@ export {
66692
67103
  is_cli_entry_point
66693
67104
  };
66694
67105
 
66695
- //# debugId=343582E63382658564756E2164756E21
67106
+ //# debugId=CC4BC332FB54011E64756E2164756E21