@rooode/dsh-plugin-preview 0.1.4 → 0.1.5

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.
package/cordis.patch.yml CHANGED
@@ -13,4 +13,16 @@
13
13
  - .json
14
14
  - .yaml
15
15
  - .yml
16
+ - .js
17
+ - .ts
18
+ - .java
19
+ - .cpp
20
+ - .c
21
+ - .h
22
+ - .hpp
23
+ - .py
24
+ - .go
25
+ - .rs
26
+ - .sh
27
+ - .sql
16
28
  maxFileSizeMb: 10
package/lib/client.js CHANGED
@@ -33,8 +33,13 @@
33
33
  const SUPPORTED_EXTENSIONS = new Set([
34
34
  '.md', '.markdown', '.mdown', '.mkdn', '.mdwn',
35
35
  '.txt', '.log', '.json', '.yaml', '.yml',
36
- '.js', '.jsx', '.ts', '.tsx', '.html', '.css', '.scss',
37
- '.py', '.sh', '.bash', '.ps1', '.sql', '.toml', '.xml'
36
+ '.js', '.jsx', '.ts', '.tsx', '.html', '.css', '.scss', '.less',
37
+ '.java', '.jav', '.jsp',
38
+ '.cpp', '.c', '.cc', '.cxx', '.h', '.hpp', '.hxx', '.inl',
39
+ '.py', '.pyw', '.ipynb',
40
+ '.go', '.rs', '.cs', '.kt',
41
+ '.sh', '.bash', '.zsh', '.ps1', '.bat', '.cmd',
42
+ '.sql', '.toml', '.xml', '.svg', '.ini', '.env', '.properties'
38
43
  ]);
39
44
 
40
45
  // =========================================================================
@@ -172,8 +177,15 @@
172
177
  if (ext === '.yaml' || ext === '.yml' || ext === '.toml' || ext === '.ini') return { icon: '⚙️', color: '#f97316' };
173
178
  if (ext === '.html' || ext === '.htm') return { icon: '🌐', color: '#ef4444' };
174
179
  if (ext === '.css' || ext === '.scss' || ext === '.less') return { icon: '#', color: '#06b6d4' };
175
- if (ext === '.py') return { icon: '🐍', color: '#38bdf8' };
176
- if (ext === '.sh' || ext === '.bash' || ext === '.ps1') return { icon: '⌨️', color: '#8b5cf6' };
180
+ if (ext === '.java' || ext === '.jav') return { icon: '', color: '#ea580c' };
181
+ if (['.cpp', '.cc', '.cxx', '.hpp', '.hxx'].includes(ext)) return { icon: 'C++', color: '#0284c7' };
182
+ if (ext === '.c' || ext === '.h') return { icon: 'C', color: '#64748b' };
183
+ if (ext === '.py' || ext === '.pyw') return { icon: '🐍', color: '#38bdf8' };
184
+ if (ext === '.go') return { icon: 'GO', color: '#00add8' };
185
+ if (ext === '.rs') return { icon: '🦀', color: '#ea580c' };
186
+ if (ext === '.cs') return { icon: 'C#', color: '#a855f7' };
187
+ if (ext === '.kt') return { icon: 'KT', color: '#7c3aed' };
188
+ if (ext === '.sh' || ext === '.bash' || ext === '.ps1' || ext === '.zsh') return { icon: '⌨️', color: '#8b5cf6' };
177
189
  if (['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp'].includes(ext)) return { icon: '🖼️', color: '#ec4899' };
178
190
  if (ext === '.log' || ext === '.txt') return { icon: '📄', color: '#64748b' };
179
191
  return { icon: '📄', color: '#94a3b8' };
@@ -187,7 +199,12 @@
187
199
  if (['.json', '.jsonc', '.json5', '.geojson', '.lock'].includes(ext)) return 'json';
188
200
  if (['.yaml', '.yml'].includes(ext)) return 'yaml';
189
201
  if (['.js', '.jsx', '.mjs', '.cjs', '.ts', '.tsx', '.mts', '.cts'].includes(ext)) return 'javascript';
190
- if (['.py', '.pyw'].includes(ext)) return 'python';
202
+ if (['.java', '.jav', '.jsp'].includes(ext)) return 'java';
203
+ if (['.cpp', '.c', '.cc', '.cxx', '.h', '.hpp', '.hxx', '.inl'].includes(ext)) return 'cpp';
204
+ if (['.py', '.pyw', '.ipynb'].includes(ext)) return 'python';
205
+ if (['.go'].includes(ext)) return 'go';
206
+ if (['.rs'].includes(ext)) return 'rust';
207
+ if (['.cs'].includes(ext)) return 'csharp';
191
208
  if (['.html', '.htm', '.svg', '.xml'].includes(ext)) return 'markup';
192
209
  if (['.css', '.scss', '.less', '.sass'].includes(ext)) return 'css';
193
210
  if (['.sh', '.bash', '.zsh', '.ps1', '.bat', '.cmd'].includes(ext)) return 'shell';
@@ -1239,19 +1256,172 @@
1239
1256
  return out;
1240
1257
  }
1241
1258
 
1259
+ function highlightJava(code) {
1260
+ if (!code) return '';
1261
+ const keywords = new Set([
1262
+ 'public', 'private', 'protected', 'class', 'interface', 'enum', 'record', 'extends',
1263
+ 'implements', 'static', 'final', 'abstract', 'void', 'return', 'if', 'else', 'for',
1264
+ 'while', 'do', 'switch', 'case', 'break', 'continue', 'default', 'new', 'this', 'super',
1265
+ 'try', 'catch', 'finally', 'throw', 'throws', 'import', 'package', 'synchronized',
1266
+ 'volatile', 'transient', 'native', 'strictfp', 'instanceof', 'assert', 'yield', 'sealed',
1267
+ 'permits', 'var', 'const', 'goto'
1268
+ ]);
1269
+ const types = new Set([
1270
+ 'int', 'long', 'short', 'byte', 'float', 'double', 'boolean', 'char', 'void',
1271
+ 'String', 'Object', 'Integer', 'Long', 'Boolean', 'Double', 'Float', 'Byte', 'Short', 'Character',
1272
+ 'List', 'Map', 'Set', 'ArrayList', 'HashMap', 'HashSet', 'LinkedList', 'TreeMap', 'TreeSet',
1273
+ 'Optional', 'Stream', 'Arrays', 'Collections', 'System', 'Thread', 'Exception', 'RuntimeException',
1274
+ 'Throwable', 'Error', 'Class', 'StringBuilder', 'StringBuffer', 'CompletableFuture', 'Future',
1275
+ 'null', 'true', 'false'
1276
+ ]);
1277
+
1278
+ const tokenRegex = /(\/\*[\s\S]*?\*\/|\/\/.*$|"""[\s\S]*?"""|"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|@[a-zA-Z0-9_.]+|\b(?:0x[0-9a-fA-F]+|\d+(?:\.\d+)?(?:[eE][+\-]?\d+)?[fFdDlL]?)\b|\b[a-zA-Z_$][a-zA-Z0-9_$]*\b|->|::|==|!=|<=|>=|&&|\|\||\+\+|--|\+=|-=|\*=|\/=|%=|&=|\|=|\^=|>>>=|>>=|<<=|[+\-*/%=!&|^~<>?:;,{}()\[\].])/gm;
1279
+
1280
+ let lastIndex = 0;
1281
+ let out = '';
1282
+ let match;
1283
+
1284
+ while ((match = tokenRegex.exec(code)) !== null) {
1285
+ const raw = match[0];
1286
+ const index = match.index;
1287
+ if (index > lastIndex) {
1288
+ out += escapeHtml(code.slice(lastIndex, index));
1289
+ }
1290
+ lastIndex = tokenRegex.lastIndex;
1291
+
1292
+ if (raw.startsWith('/*') || raw.startsWith('//')) {
1293
+ out += '<span class="tok-comment">' + escapeHtml(raw) + '</span>';
1294
+ } else if (raw.startsWith('"""') || raw.startsWith('"') || raw.startsWith("'")) {
1295
+ out += '<span class="tok-string">' + escapeHtml(raw) + '</span>';
1296
+ } else if (raw.startsWith('@')) {
1297
+ out += '<span class="tok-attr">' + escapeHtml(raw) + '</span>';
1298
+ } else if (/^\d|^0x/.test(raw)) {
1299
+ out += '<span class="tok-number">' + escapeHtml(raw) + '</span>';
1300
+ } else if (/^[a-zA-Z_$]/.test(raw)) {
1301
+ if (keywords.has(raw)) {
1302
+ out += '<span class="tok-keyword">' + escapeHtml(raw) + '</span>';
1303
+ } else if (types.has(raw)) {
1304
+ out += '<span class="tok-type">' + escapeHtml(raw) + '</span>';
1305
+ } else {
1306
+ const remainder = code.slice(lastIndex);
1307
+ if (/^\s*\(/.test(remainder)) {
1308
+ out += '<span class="tok-func">' + escapeHtml(raw) + '</span>';
1309
+ } else {
1310
+ out += escapeHtml(raw);
1311
+ }
1312
+ }
1313
+ } else if (/^(->|::|==|!=|<=|>=|&&|\|\||\+\+|--|\+=|-=|\*=|\/=|%=|&=|\|=|\^=|>>>=|>>=|<<=|[+\-*/%=!&|^~<>])$/.test(raw)) {
1314
+ out += '<span class="tok-operator">' + escapeHtml(raw) + '</span>';
1315
+ } else if (/^[{}()\[\]]$/.test(raw)) {
1316
+ out += '<span class="tok-bracket">' + escapeHtml(raw) + '</span>';
1317
+ } else if (/^[,;:?]$/.test(raw)) {
1318
+ out += '<span class="tok-punctuation">' + escapeHtml(raw) + '</span>';
1319
+ } else {
1320
+ out += escapeHtml(raw);
1321
+ }
1322
+ }
1323
+
1324
+ if (lastIndex < code.length) {
1325
+ out += escapeHtml(code.slice(lastIndex));
1326
+ }
1327
+ return out;
1328
+ }
1329
+
1330
+ function highlightCpp(code) {
1331
+ if (!code) return '';
1332
+ const keywords = new Set([
1333
+ 'class', 'struct', 'union', 'enum', 'template', 'typename', 'namespace', 'using',
1334
+ 'typedef', 'public', 'private', 'protected', 'virtual', 'override', 'final', 'const',
1335
+ 'constexpr', 'consteval', 'constinit', 'static', 'inline', 'auto', 'void', 'return',
1336
+ 'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'break', 'continue', 'default',
1337
+ 'new', 'delete', 'this', 'try', 'catch', 'throw', 'noexcept', 'explicit', 'friend',
1338
+ 'mutable', 'volatile', 'concept', 'requires', 'co_await', 'co_yield', 'co_return',
1339
+ 'decltype', 'sizeof', 'alignas', 'alignof', 'static_cast', 'dynamic_cast',
1340
+ 'reinterpret_cast', 'const_cast', 'operator', 'export', 'import', 'module'
1341
+ ]);
1342
+ const types = new Set([
1343
+ 'int', 'long', 'short', 'char', 'float', 'double', 'bool', 'void', 'wchar_t', 'char8_t',
1344
+ 'char16_t', 'char32_t', 'size_t', 'int8_t', 'int16_t', 'int32_t', 'int64_t',
1345
+ 'uint8_t', 'uint16_t', 'uint32_t', 'uint64_t', 'nullptr', 'true', 'false',
1346
+ 'string', 'wstring', 'vector', 'map', 'unordered_map', 'set', 'unordered_set',
1347
+ 'pair', 'tuple', 'unique_ptr', 'shared_ptr', 'weak_ptr', 'make_unique', 'make_shared',
1348
+ 'std', 'cout', 'cin', 'cerr', 'endl', 'array', 'deque', 'list', 'queue', 'stack'
1349
+ ]);
1350
+
1351
+ const tokenRegex = /(\/\*[\s\S]*?\*\/|\/\/.*$|#(?:include|define|ifdef|ifndef|endif|if|else|elif|pragma|undef|error)\b.*$|R"\(.*?\)"|"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\b(?:0x[0-9a-fA-F]+|\d+(?:\.\d+)?(?:[eE][+\-]?\d+)?[uUlLfF]?)\b|\b[a-zA-Z_][a-zA-Z0-9_]*\b|::|->\*|->|==|!=|<=|>=|<=>|&&|\|\||\+\+|--|\+=|-=|\*=|\/=|%=|&=|\|=|\^=|>>=|<<=|<<|>>|[+\-*/%=!&|^~<>?:;,{}()\[\].])/gm;
1352
+
1353
+ let lastIndex = 0;
1354
+ let out = '';
1355
+ let match;
1356
+
1357
+ while ((match = tokenRegex.exec(code)) !== null) {
1358
+ const raw = match[0];
1359
+ const index = match.index;
1360
+ if (index > lastIndex) {
1361
+ out += escapeHtml(code.slice(lastIndex, index));
1362
+ }
1363
+ lastIndex = tokenRegex.lastIndex;
1364
+
1365
+ if (raw.startsWith('/*') || raw.startsWith('//')) {
1366
+ out += '<span class="tok-comment">' + escapeHtml(raw) + '</span>';
1367
+ } else if (raw.startsWith('#')) {
1368
+ const spaceIdx = raw.indexOf(' ');
1369
+ if (spaceIdx !== -1) {
1370
+ const dir = raw.slice(0, spaceIdx);
1371
+ const rest = raw.slice(spaceIdx);
1372
+ out += '<span class="tok-keyword">' + escapeHtml(dir) + '</span><span class="tok-string">' + escapeHtml(rest) + '</span>';
1373
+ } else {
1374
+ out += '<span class="tok-keyword">' + escapeHtml(raw) + '</span>';
1375
+ }
1376
+ } else if (raw.startsWith('R"') || raw.startsWith('"') || raw.startsWith("'")) {
1377
+ out += '<span class="tok-string">' + escapeHtml(raw) + '</span>';
1378
+ } else if (/^\d|^0x/.test(raw)) {
1379
+ out += '<span class="tok-number">' + escapeHtml(raw) + '</span>';
1380
+ } else if (/^[a-zA-Z_]/.test(raw)) {
1381
+ if (keywords.has(raw)) {
1382
+ out += '<span class="tok-keyword">' + escapeHtml(raw) + '</span>';
1383
+ } else if (types.has(raw)) {
1384
+ out += '<span class="tok-type">' + escapeHtml(raw) + '</span>';
1385
+ } else {
1386
+ const remainder = code.slice(lastIndex);
1387
+ if (/^\s*\(/.test(remainder)) {
1388
+ out += '<span class="tok-func">' + escapeHtml(raw) + '</span>';
1389
+ } else {
1390
+ out += escapeHtml(raw);
1391
+ }
1392
+ }
1393
+ } else if (/^(::|->\*|->|==|!=|<=|>=|<=>|&&|\|\||\+\+|--|\+=|-=|\*=|\/=|%=|&=|\|=|\^=|>>=|<<=|<<|>>|[+\-*/%=!&|^~<>])$/.test(raw)) {
1394
+ out += '<span class="tok-operator">' + escapeHtml(raw) + '</span>';
1395
+ } else if (/^[{}()\[\]]$/.test(raw)) {
1396
+ out += '<span class="tok-bracket">' + escapeHtml(raw) + '</span>';
1397
+ } else if (/^[,;:?]$/.test(raw)) {
1398
+ out += '<span class="tok-punctuation">' + escapeHtml(raw) + '</span>';
1399
+ } else {
1400
+ out += escapeHtml(raw);
1401
+ }
1402
+ }
1403
+
1404
+ if (lastIndex < code.length) {
1405
+ out += escapeHtml(code.slice(lastIndex));
1406
+ }
1407
+ return out;
1408
+ }
1409
+
1242
1410
  function highlightPython(code) {
1243
1411
  if (!code) return '';
1244
1412
  const pyKeywords = new Set([
1245
1413
  'def', 'class', 'import', 'from', 'return', 'if', 'elif', 'else', 'for', 'while',
1246
1414
  'try', 'except', 'finally', 'raise', 'with', 'as', 'lambda', 'pass', 'yield',
1247
- 'async', 'await', 'global', 'nonlocal', 'assert', 'del', 'in', 'is', 'not', 'and', 'or'
1415
+ 'async', 'await', 'global', 'nonlocal', 'assert', 'del', 'in', 'is', 'not', 'and', 'or',
1416
+ 'match', 'case'
1248
1417
  ]);
1249
1418
  const pyBuiltins = new Set([
1250
1419
  'True', 'False', 'None', 'self', 'cls', 'print', 'len', 'range', 'dict', 'list',
1251
- 'set', 'tuple', 'str', 'int', 'float', 'bool', 'type', 'isinstance', 'enumerate', 'zip'
1420
+ 'set', 'tuple', 'str', 'int', 'float', 'bool', 'type', 'isinstance', 'enumerate', 'zip',
1421
+ 'super', 'sum', 'min', 'max', 'any', 'all', 'open', 'map', 'filter'
1252
1422
  ]);
1253
1423
 
1254
- const tokenRegex = /("""[\s\S]*?"""|'''[\s\S]*?'''|#.*$|f?"(?:\\[\s\S]|[^"\\])*"|f?'(?:\\[\s\S]|[^'\\])*'|\b\d+(?:\.\d+)?\b|\b[a-zA-Z_][a-zA-Z0-9_]*\b|==|!=|<=|>=|\+=|-=|\*=|\/=|->|[+\-*/%=&|^~<>?:;,{}()\[\].])/gm;
1424
+ const tokenRegex = /("""[\s\S]*?"""|'''[\s\S]*?'''|#.*$|@[a-zA-Z0-9_.]+|f?"(?:\\[\s\S]|[^"\\])*"|f?'(?:\\[\s\S]|[^'\\])*'|\b\d+(?:\.\d+)?\b|\b[a-zA-Z_][a-zA-Z0-9_]*\b|==|!=|<=|>=|\+=|-=|\*=|\/=|->|[+\-*/%=&|^~<>?:;,{}()\[\].])/gm;
1255
1425
 
1256
1426
  let lastIndex = 0;
1257
1427
  let out = '';
@@ -1269,6 +1439,8 @@
1269
1439
  out += '<span class="tok-comment">' + escapeHtml(raw) + '</span>';
1270
1440
  } else if (raw.startsWith('"""') || raw.startsWith("'''") || raw.startsWith('"') || raw.startsWith("'") || raw.startsWith('f"') || raw.startsWith("f'")) {
1271
1441
  out += '<span class="tok-string">' + escapeHtml(raw) + '</span>';
1442
+ } else if (raw.startsWith('@')) {
1443
+ out += '<span class="tok-attr">' + escapeHtml(raw) + '</span>';
1272
1444
  } else if (/^\d/.test(raw)) {
1273
1445
  out += '<span class="tok-number">' + escapeHtml(raw) + '</span>';
1274
1446
  } else if (/^[a-zA-Z_]/.test(raw)) {
@@ -1347,6 +1519,22 @@
1347
1519
  .replace(/(--.*$)/gm, '<span class="tok-comment">$1</span>')
1348
1520
  .replace(/('[^']*')/g, '<span class="tok-string">$1</span>');
1349
1521
  }
1522
+ if (category === 'go') {
1523
+ const goKeywords = /\b(package|import|func|return|var|const|type|struct|interface|map|chan|go|defer|if|else|for|range|switch|case|default|select|break|continue|fallthrough)\b/g;
1524
+ return escapeHtml(code)
1525
+ .replace(/(\b(?:string|int|int64|int32|uint|uint64|byte|rune|bool|float32|float64|error|nil|true|false)\b)/g, '<span class="tok-type">$1</span>')
1526
+ .replace(goKeywords, '<span class="tok-keyword">$1</span>')
1527
+ .replace(/(\/\/.*$)/gm, '<span class="tok-comment">$1</span>')
1528
+ .replace(/("(?:\\[\s\S]|[^"\\])*")/g, '<span class="tok-string">$1</span>');
1529
+ }
1530
+ if (category === 'rust') {
1531
+ const rsKeywords = /\b(fn|let|mut|pub|struct|enum|impl|trait|type|use|mod|crate|return|if|else|match|loop|while|for|in|break|continue|async|await|where|unsafe|as|ref|move)\b/g;
1532
+ return escapeHtml(code)
1533
+ .replace(/(\b(?:i8|i16|i32|i64|i128|isize|u8|u16|u32|u64|u128|usize|f32|f64|bool|char|str|String|Vec|Option|Result|Some|None|Ok|Err|true|false)\b)/g, '<span class="tok-type">$1</span>')
1534
+ .replace(rsKeywords, '<span class="tok-keyword">$1</span>')
1535
+ .replace(/(\/\/.*$)/gm, '<span class="tok-comment">$1</span>')
1536
+ .replace(/("(?:\\[\s\S]|[^"\\])*")/g, '<span class="tok-string">$1</span>');
1537
+ }
1350
1538
  const lines = code.split('\n');
1351
1539
  return lines.map(line => {
1352
1540
  const commentIdx = line.indexOf('#');
@@ -1371,10 +1559,12 @@
1371
1559
  if (category === 'json') return highlightJSON(rawCode);
1372
1560
  if (category === 'yaml') return highlightYAML(rawCode);
1373
1561
  if (category === 'javascript') return highlightJS(rawCode);
1562
+ if (category === 'java') return highlightJava(rawCode);
1563
+ if (category === 'cpp') return highlightCpp(rawCode);
1374
1564
  if (category === 'python') return highlightPython(rawCode);
1375
1565
  if (category === 'markup') return highlightHTML(rawCode);
1376
1566
  if (category === 'css') return highlightCSS(rawCode);
1377
- if (category === 'shell' || category === 'config' || category === 'sql') return highlightGenericCode(rawCode, category);
1567
+ if (category === 'shell' || category === 'config' || category === 'sql' || category === 'go' || category === 'rust' || category === 'csharp') return highlightGenericCode(rawCode, category);
1378
1568
  return escapeHtml(rawCode);
1379
1569
  }
1380
1570
 
@@ -1504,7 +1694,7 @@
1504
1694
  lines.forEach((line, idx) => {
1505
1695
  const lineNum = idx + 1;
1506
1696
  const trimmed = line.trim();
1507
- if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*')) return;
1697
+ if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*') || trimmed.startsWith('return ')) return;
1508
1698
 
1509
1699
  const classMatch = trimmed.match(/\bclass\s+([a-zA-Z0-9_$]+)/);
1510
1700
  if (classMatch) {
@@ -1534,15 +1724,68 @@
1534
1724
  symbols.push({ id: `line-${lineNum}`, name: 'default export', kind: 'export', line: lineNum, text: `📦 export default` });
1535
1725
  }
1536
1726
  });
1727
+ } else if (category === 'java') {
1728
+ lines.forEach((line, idx) => {
1729
+ const lineNum = idx + 1;
1730
+ const trimmed = line.trim();
1731
+ if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*') || trimmed.startsWith('throw ') || trimmed.startsWith('return ')) return;
1732
+
1733
+ const pkgMatch = trimmed.match(/^package\s+([a-zA-Z0-9_.]+);/);
1734
+ if (pkgMatch) {
1735
+ symbols.push({ id: `line-${lineNum}`, name: pkgMatch[1], kind: 'package', line: lineNum, text: `📦 package ${pkgMatch[1]}` });
1736
+ return;
1737
+ }
1738
+
1739
+ const classMatch = trimmed.match(/\b(?:public|protected|private|static|final|abstract\s+)*(class|interface|enum|record)\s+([a-zA-Z0-9_]+)/);
1740
+ if (classMatch) {
1741
+ const typeIcon = classMatch[1] === 'interface' ? '🏷️' : classMatch[1] === 'enum' ? '🔢' : '🔷';
1742
+ symbols.push({ id: `line-${lineNum}`, name: classMatch[2], kind: classMatch[1], line: lineNum, text: `${typeIcon} ${classMatch[1]} ${classMatch[2]}` });
1743
+ return;
1744
+ }
1745
+
1746
+ const methodMatch = trimmed.match(/^(?:@\w+\s+)*(?:public|protected|private|static|final|synchronized|abstract|default|native|\s)*(?:<[^>]+>\s+)?([a-zA-Z0-9_<>[],.\s]+(?:\s*\[\s*\])?\s+)?([a-zA-Z0-9_]+)\s*\([^)]*\)\s*(?:throws\s+[a-zA-Z0-9_,\s]+)?\s*\{?$/);
1747
+ if (methodMatch) {
1748
+ const name = methodMatch[2];
1749
+ if (!['if', 'for', 'while', 'switch', 'catch', 'return', 'throw', 'new', 'this', 'super'].includes(name)) {
1750
+ symbols.push({ id: `line-${lineNum}`, name, kind: 'method', line: lineNum, text: `⚡ ${name}()` });
1751
+ }
1752
+ }
1753
+ });
1754
+ } else if (category === 'cpp') {
1755
+ lines.forEach((line, idx) => {
1756
+ const lineNum = idx + 1;
1757
+ const trimmed = line.trim();
1758
+ if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*') || trimmed.startsWith('#') || trimmed.startsWith('throw ') || trimmed.startsWith('return ')) return;
1759
+
1760
+ const nsMatch = trimmed.match(/^namespace\s+([a-zA-Z0-9_:]+)/);
1761
+ if (nsMatch) {
1762
+ symbols.push({ id: `line-${lineNum}`, name: nsMatch[1], kind: 'namespace', line: lineNum, text: `📦 namespace ${nsMatch[1]}` });
1763
+ return;
1764
+ }
1765
+
1766
+ const classMatch = trimmed.match(/\b(class|struct|union|enum\s+class|enum)\s+([a-zA-Z0-9_]+)/);
1767
+ if (classMatch && !trimmed.endsWith(';')) {
1768
+ symbols.push({ id: `line-${lineNum}`, name: classMatch[2], kind: classMatch[1], line: lineNum, text: `🔷 ${classMatch[1]} ${classMatch[2]}` });
1769
+ return;
1770
+ }
1771
+
1772
+ const funcMatch = trimmed.match(/^(?:(?:inline|virtual|static|constexpr|const|explicit|friend|auto|[a-zA-Z0-9_:<>&*~]+)\s+)+([a-zA-Z0-9_~]+)\s*\([^)]*\)\s*(?:const|noexcept|override|final|\s)*\s*\{?$/);
1773
+ if (funcMatch && !['if', 'for', 'while', 'switch', 'catch', 'return', 'else', 'sizeof', 'decltype'].includes(funcMatch[1])) {
1774
+ symbols.push({ id: `line-${lineNum}`, name: funcMatch[1], kind: 'function', line: lineNum, text: `⚡ fn ${funcMatch[1]}()` });
1775
+ }
1776
+ });
1537
1777
  } else if (category === 'python') {
1538
1778
  lines.forEach((line, idx) => {
1539
1779
  const lineNum = idx + 1;
1540
- const classMatch = line.match(/^class\s+([a-zA-Z0-9_]+)/);
1780
+ const trimmed = line.trim();
1781
+ if (trimmed.startsWith('#')) return;
1782
+
1783
+ const classMatch = trimmed.match(/^classs+([a-zA-Z0-9_]+)/);
1541
1784
  if (classMatch) {
1542
1785
  symbols.push({ id: `line-${lineNum}`, name: classMatch[1], kind: 'class', line: lineNum, text: `🔷 class ${classMatch[1]}` });
1543
1786
  return;
1544
1787
  }
1545
- const funcMatch = line.match(/^(\s*)(?:async\s+)?def\s+([a-zA-Z0-9_]+)/);
1788
+ const funcMatch = line.match(/^(\s*)(?:async\s+)?defs+([a-zA-Z0-9_]+)/);
1546
1789
  if (funcMatch) {
1547
1790
  const prefix = funcMatch[1].length > 0 ? ' ' : '';
1548
1791
  symbols.push({ id: `line-${lineNum}`, name: funcMatch[2], kind: 'function', line: lineNum, text: `${prefix}⚡ def ${funcMatch[2]}()` });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rooode/dsh-plugin-preview",
3
- "version": "0.1.4",
4
- "description": "DeepSeek Harness Markdown 文档与工作空间文件浏览器右侧预览插件 (支持工作区文件树、JSON 交互结构树/格式化、YAML/JS/TS/Python 多语言语法高亮、代码符号大纲、自动换行与多标签 FileTabs)",
3
+ "version": "0.1.5",
4
+ "description": "DeepSeek Harness Markdown 文档与工作空间文件浏览器右侧预览插件 (支持工作区文件树、JSON 交互结构树/格式化、Java/C++/Python/JS/TS/YAML/Go/Rust 多语言语法高亮与符号大纲、自动换行与多标签 FileTabs)",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",