I have extended vscode with an extension #23

Merged
probablycorey merged 15 commits from vscode into main 2025-11-06 00:20:29 +00:00
11 changed files with 312 additions and 0 deletions
Showing only changes of commit f4cbe54a88 - Show all commits

3
vscode-extension/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules
dist
*.vsix

17
vscode-extension/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,17 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "bun: compile"
}
]
}

30
vscode-extension/.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,30 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "bun: compile",
"command": "bun",
"args": ["run", "compile"],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": "$tsc",
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "shell",
"label": "bun: watch",
"command": "bun",
"args": ["run", "watch"],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": "$tsc-watch",
"isBackground": true
}
]
}

View File

@ -0,0 +1,5 @@
.vscode/**
src/**
tsconfig.json
node_modules/**
*.map

22
vscode-extension/bun.lock Normal file
View File

@ -0,0 +1,22 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "shrimp",
"devDependencies": {
"@types/node": "22.x",
"@types/vscode": "^1.105.0",
"typescript": "^5.9.3",
},
},
},
"packages": {
"@types/node": ["@types/node@22.19.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-xpr/lmLPQEj+TUnHmR+Ab91/glhJvsqcjB+yY0Ix9GO70H6Lb4FHH5GeqdOE5btAx7eIMwuHkp4H2MSkLcqWbA=="],
"@types/vscode": ["@types/vscode@1.105.0", "", {}, "sha512-Lotk3CTFlGZN8ray4VxJE7axIyLZZETQJVWi/lYoUVQuqfRxlQhVOfoejsD2V3dVXPSbS15ov5ZyowMAzgUqcw=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
}
}

BIN
vscode-extension/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

View File

@ -0,0 +1,24 @@
{
"comments": {
"lineComment": {
"comment": "#"
}
},
"brackets": [
["(", ")"],
["[", "]"]
],
"autoClosingPairs": [
{ "open": "(", "close": ")" },
{ "open": "[", "close": "]" },
{ "open": "'", "close": "'", "notIn": ["string"] },
{ "open": "\"", "close": "\"", "notIn": ["string"] }
],
"surroundingPairs": [
["(", ")"],
["[", "]"],
["'", "'"],
["\"", "\""]
],
"wordPattern": "([a-z][a-z0-9-]*)|(-?\\d+\\.?\\d*)"
}

View File

@ -0,0 +1,47 @@
{
"name": "shrimp",
"version": "0.0.1",
"main": "./dist/extension.js",
"devDependencies": {
"@types/vscode": "^1.105.0",
"@types/node": "22.x",
"typescript": "^5.9.3"
},
"categories": [
"Programming Languages"
],
"contributes": {
"languages": [
{
"id": "shrimp",
"aliases": [
"Shrimp",
"shrimp"
],
"extensions": [
".sh"
],
"configuration": "./language-configuration.json"
}
],
"configurationDefaults": {
"[shrimp]": {
"editor.semanticHighlighting.enabled": true
}
}
},
"description": "Language support for Shrimp shell scripting language",
"displayName": "Shrimp",
"engines": {
"vscode": "^1.105.0"
},
"icon": "icon.png",
"publisher": "shrimp-lang",
"scripts": {
"vscode:prepublish": "bun run package",
"compile": "bun build src/extension.ts --outdir dist --target node --format cjs --external vscode",
"watch": "bun build src/extension.ts --outdir dist --target node --format cjs --external vscode --watch",
"package": "bun build src/extension.ts --outdir dist --target node --format cjs --external vscode --minify",
"check-types": "tsc --noEmit"
}
}

View File

@ -0,0 +1,30 @@
import * as vscode from 'vscode'
import { ShrimpSemanticTokensProvider, legend } from './semanticTokens'
import { parser } from '../../src/parser/shrimp'
// This method is called when your extension is activated
export function activate(context: vscode.ExtensionContext) {
console.log('Shrimp extension is now active!')
console.log('Parser loaded:', typeof parser, parser)
// Test the parser
try {
const testTree = parser.parse('x = 42')
console.log('Parser test successful:', testTree.topNode.toString())
} catch (error) {
console.error('Parser test failed:', error)
}
// Register semantic tokens provider for Shrimp language
const provider = new ShrimpSemanticTokensProvider()
const selector: vscode.DocumentSelector = { language: 'shrimp', scheme: 'file' }
const disposable = vscode.languages.registerDocumentSemanticTokensProvider(selector, provider, legend)
console.log('Registered semantic tokens provider:', disposable)
context.subscriptions.push(disposable)
console.log('Legend token types:', legend.tokenTypes)
}
// This method is called when your extension is deactivated
export function deactivate() {}

View File

@ -0,0 +1,118 @@
import * as vscode from 'vscode'
import { parser } from '../../src/parser/shrimp'
import { Tree, SyntaxNode } from '@lezer/common'
// Define the token types we'll use
const tokenTypes = [
'function',
'variable',
'string',
'number',
'operator',
'keyword',
'parameter',
'property',
'regexp',
]
const tokenModifiers: string[] = []
export const legend = new vscode.SemanticTokensLegend(tokenTypes, tokenModifiers)
export class ShrimpSemanticTokensProvider implements vscode.DocumentSemanticTokensProvider {
async provideDocumentSemanticTokens(
document: vscode.TextDocument,
_token: vscode.CancellationToken
): Promise<vscode.SemanticTokens> {
try {
console.log('provideDocumentSemanticTokens called for:', document.fileName)
const tokensBuilder = new vscode.SemanticTokensBuilder(legend)
const text = document.getText()
console.log('Document text:', text)
console.log('About to parse with parser:', typeof parser)
const tree: Tree = parser.parse(text)
console.log('Parsed tree:', tree.topNode.toString())
this.walkTree(tree.topNode, document, tokensBuilder)
const result = tokensBuilder.build()
console.log('Built tokens, data length:', result.data.length)
return result
} catch (error) {
console.error('Error in provideDocumentSemanticTokens:', error)
throw error
}
}
// Map Lezer node types to semantic token types
walkTree(node: SyntaxNode, document: vscode.TextDocument, builder: vscode.SemanticTokensBuilder) {
const tokenType = this.getTokenType(node.type.name)
if (tokenType !== undefined) {
const start = document.positionAt(node.from)
const length = node.to - node.from
builder.push(start.line, start.character, length, tokenType, 0)
}
// Recursively walk children
let child = node.firstChild
while (child) {
this.walkTree(child, document, builder)
child = child.nextSibling
}
}
getTokenType(nodeTypeName: string): number | undefined {
// Map Lezer node names to VSCode semantic token types
switch (nodeTypeName) {
case 'FunctionCall':
case 'FunctionDef':
return tokenTypes.indexOf('function')
case 'Identifier':
case 'AssignableIdentifier':
case 'FunctionCallOrIdentifier':
return tokenTypes.indexOf('variable')
case 'String':
case 'StringFragment':
case 'Word':
return tokenTypes.indexOf('string')
case 'Number':
return tokenTypes.indexOf('number')
case 'Plus':
case 'Minus':
case 'Star':
case 'Slash':
case 'Eq':
case 'EqEq':
case 'Neq':
case 'Lt':
case 'Lte':
case 'Gt':
case 'Gte':
case 'Modulo':
case 'And':
case 'Or':
return tokenTypes.indexOf('operator')
case 'keyword':
case 'Do':
return tokenTypes.indexOf('keyword')
case 'Params':
case 'NamedParam':
return tokenTypes.indexOf('parameter')
case 'DotGet':
return tokenTypes.indexOf('property')
case 'Regex':
return tokenTypes.indexOf('regexp')
default:
return undefined
}
}
}

View File

@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "commonjs",
"moduleResolution": "node",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}