...
This commit is contained in:
@@ -1,12 +1,10 @@
|
|||||||
using NubLang.Ast;
|
using NubLang.Ast;
|
||||||
using NubLang.Generation;
|
|
||||||
using NubLang.Syntax;
|
using NubLang.Syntax;
|
||||||
using OmniSharp.Extensions.LanguageServer.Protocol;
|
using OmniSharp.Extensions.LanguageServer.Protocol;
|
||||||
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
|
|
||||||
|
|
||||||
namespace NubLang.LSP;
|
namespace NubLang.LSP;
|
||||||
|
|
||||||
public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher, ILanguageServerFacade server)
|
public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher)
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, SyntaxTree> _syntaxTrees = new();
|
private readonly Dictionary<string, SyntaxTree> _syntaxTrees = new();
|
||||||
private readonly Dictionary<string, CompilationUnit> _compilationUnits = new();
|
private readonly Dictionary<string, CompilationUnit> _compilationUnits = new();
|
||||||
@@ -29,47 +27,37 @@ public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher, ILangua
|
|||||||
_syntaxTrees[path] = parseResult;
|
_syntaxTrees[path] = parseResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
Generate();
|
foreach (var (fsPath, syntaxTree) in _syntaxTrees)
|
||||||
|
{
|
||||||
|
var modules = Module.Collect(_syntaxTrees.Select(x => x.Value).ToList());
|
||||||
|
|
||||||
|
var typeChecker = new TypeChecker(syntaxTree, modules);
|
||||||
|
var result = typeChecker.Check();
|
||||||
|
diagnosticsPublisher.Publish(fsPath, typeChecker.Diagnostics);
|
||||||
|
_compilationUnits[fsPath] = result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateFile(DocumentUri path)
|
public void UpdateFile(DocumentUri path)
|
||||||
{
|
{
|
||||||
var fsPath = path.GetFileSystemPath();
|
var fsPath = path.GetFileSystemPath();
|
||||||
|
|
||||||
var text = File.ReadAllText(fsPath);
|
var text = File.ReadAllText(fsPath);
|
||||||
var tokenizer = new Tokenizer(fsPath, text);
|
var tokenizer = new Tokenizer(fsPath, text);
|
||||||
|
|
||||||
tokenizer.Tokenize();
|
tokenizer.Tokenize();
|
||||||
diagnosticsPublisher.Publish(path, tokenizer.Diagnostics);
|
diagnosticsPublisher.Publish(path, tokenizer.Diagnostics);
|
||||||
|
|
||||||
var parser = new Parser();
|
var parser = new Parser();
|
||||||
var parseResult = parser.Parse(tokenizer.Tokens);
|
var syntaxTree = parser.Parse(tokenizer.Tokens);
|
||||||
diagnosticsPublisher.Publish(path, parser.Diagnostics);
|
diagnosticsPublisher.Publish(path, parser.Diagnostics);
|
||||||
|
_syntaxTrees[fsPath] = syntaxTree;
|
||||||
|
|
||||||
_syntaxTrees[fsPath] = parseResult;
|
|
||||||
|
|
||||||
Generate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Generate()
|
|
||||||
{
|
|
||||||
var modules = Module.Collect(_syntaxTrees.Select(x => x.Value).ToList());
|
var modules = Module.Collect(_syntaxTrees.Select(x => x.Value).ToList());
|
||||||
|
|
||||||
foreach (var (fsPath, syntaxTree) in _syntaxTrees)
|
var typeChecker = new TypeChecker(syntaxTree, modules);
|
||||||
{
|
var result = typeChecker.Check();
|
||||||
var typeChecker = new TypeChecker(syntaxTree, modules);
|
diagnosticsPublisher.Publish(fsPath, typeChecker.Diagnostics);
|
||||||
var result = typeChecker.Check();
|
_compilationUnits[fsPath] = result;
|
||||||
diagnosticsPublisher.Publish(fsPath, typeChecker.Diagnostics);
|
|
||||||
_compilationUnits[fsPath] = result;
|
|
||||||
|
|
||||||
var generator = new Generator(result);
|
|
||||||
var c = generator.Emit();
|
|
||||||
|
|
||||||
server.SendNotification("nub/output", new
|
|
||||||
{
|
|
||||||
content = c,
|
|
||||||
path = fsPath
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveFile(DocumentUri path)
|
public void RemoveFile(DocumentUri path)
|
||||||
@@ -79,11 +67,6 @@ public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher, ILangua
|
|||||||
_compilationUnits.Remove(fsPath);
|
_compilationUnits.Remove(fsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, CompilationUnit> GetCompilationUnits()
|
|
||||||
{
|
|
||||||
return _compilationUnits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompilationUnit? GetCompilationUnit(DocumentUri path)
|
public CompilationUnit? GetCompilationUnit(DocumentUri path)
|
||||||
{
|
{
|
||||||
return _compilationUnits.GetValueOrDefault(path.GetFileSystemPath());
|
return _compilationUnits.GetValueOrDefault(path.GetFileSystemPath());
|
||||||
|
|||||||
4191
vscode-lsp/package-lock.json
generated
4191
vscode-lsp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,12 @@
|
|||||||
"Programming Languages"
|
"Programming Languages"
|
||||||
],
|
],
|
||||||
"main": "./out/extension.js",
|
"main": "./out/extension.js",
|
||||||
|
"files": [
|
||||||
|
"out",
|
||||||
|
"server",
|
||||||
|
"syntaxes",
|
||||||
|
"language-configuration.json"
|
||||||
|
],
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"languages": [
|
"languages": [
|
||||||
{
|
{
|
||||||
@@ -31,31 +37,17 @@
|
|||||||
"scopeName": "source.nub",
|
"scopeName": "source.nub",
|
||||||
"path": "./syntaxes/nub.tmLanguage.json"
|
"path": "./syntaxes/nub.tmLanguage.json"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"commands": [
|
|
||||||
{
|
|
||||||
"command": "nub.openOutput",
|
|
||||||
"title": "Nub: Show Output",
|
|
||||||
"icon": "$(open-preview)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"menus": {
|
|
||||||
"editor/title": [
|
|
||||||
{
|
|
||||||
"command": "nub.openOutput",
|
|
||||||
"when": "editorLangId == nub || resourceExtname == .nub",
|
|
||||||
"group": "navigation"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -p ./",
|
"build": "tsc -p ./",
|
||||||
"watch": "tsc -watch -p ./"
|
"watch": "tsc -watch -p ./",
|
||||||
|
"package": "vsce package"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "22.x",
|
"@types/node": "22.x",
|
||||||
"@types/vscode": "^1.105.0",
|
"@types/vscode": "^1.105.0",
|
||||||
|
"@vscode/vsce": "^3.6.2",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
Binary file not shown.
@@ -3,10 +3,8 @@ import vscode from 'vscode';
|
|||||||
import { LanguageClient, TransportKind } from 'vscode-languageclient/node';
|
import { LanguageClient, TransportKind } from 'vscode-languageclient/node';
|
||||||
|
|
||||||
let client: LanguageClient;
|
let client: LanguageClient;
|
||||||
let outputPanel: vscode.WebviewPanel | undefined;
|
|
||||||
const outputCache = new Map<string, string>();
|
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export async function activate(context: vscode.ExtensionContext) {
|
||||||
const serverExecutable = path.join(context.asAbsolutePath('server'), "nublsp");
|
const serverExecutable = path.join(context.asAbsolutePath('server'), "nublsp");
|
||||||
|
|
||||||
client = new LanguageClient(
|
client = new LanguageClient(
|
||||||
@@ -34,129 +32,9 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
client.onNotification("nub/output", (params: { path: string, content: string }) => {
|
|
||||||
const normalizedPath = vscode.Uri.file(params.path).fsPath;
|
|
||||||
outputCache.set(normalizedPath, params.content);
|
|
||||||
|
|
||||||
if (outputPanel && vscode.window.activeTextEditor) {
|
|
||||||
const activePath = vscode.window.activeTextEditor.document.uri.fsPath;
|
|
||||||
if (activePath === normalizedPath) {
|
|
||||||
updateOutputPanel(params.content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const openOutputCommand = vscode.commands.registerCommand('nub.openOutput', async () => {
|
|
||||||
const editor = vscode.window.activeTextEditor;
|
|
||||||
|
|
||||||
if (!editor) {
|
|
||||||
vscode.window.showWarningMessage('No active editor found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filePath = editor.document.uri.fsPath;
|
|
||||||
const cachedOutput = outputCache.get(filePath);
|
|
||||||
|
|
||||||
if (outputPanel) {
|
|
||||||
outputPanel.reveal(vscode.ViewColumn.Beside);
|
|
||||||
} else {
|
|
||||||
outputPanel = vscode.window.createWebviewPanel(
|
|
||||||
'nubOutput',
|
|
||||||
'C Output',
|
|
||||||
vscode.ViewColumn.Beside,
|
|
||||||
{
|
|
||||||
enableScripts: true,
|
|
||||||
retainContextWhenHidden: true
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
outputPanel.onDidDispose(() => {
|
|
||||||
outputPanel = undefined;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cachedOutput) {
|
|
||||||
updateOutputPanel(cachedOutput);
|
|
||||||
} else {
|
|
||||||
updateOutputPanel('// Waiting for C output...');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const changeEditorSubscription = vscode.window.onDidChangeActiveTextEditor(editor => {
|
|
||||||
if (outputPanel && editor) {
|
|
||||||
const filePath = editor.document.uri.fsPath;
|
|
||||||
const cachedOutput = outputCache.get(filePath);
|
|
||||||
|
|
||||||
if (cachedOutput) {
|
|
||||||
updateOutputPanel(cachedOutput);
|
|
||||||
} else {
|
|
||||||
updateOutputPanel('// No C output available for this file');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
context.subscriptions.push(openOutputCommand, changeEditorSubscription);
|
|
||||||
|
|
||||||
client.start();
|
client.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateOutputPanel(content: string) {
|
|
||||||
if (!outputPanel) return;
|
|
||||||
|
|
||||||
outputPanel.webview.html = getWebviewContent(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWebviewContent(content: string): string {
|
|
||||||
const escapedContent = content
|
|
||||||
.replace(/&/g, '&')
|
|
||||||
.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>')
|
|
||||||
.replace(/"/g, '"')
|
|
||||||
.replace(/'/g, ''');
|
|
||||||
|
|
||||||
return `<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Nub C Output</title>
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/vs2015.min.css">
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 16px;
|
|
||||||
font-family: 'Consolas', 'Courier New', monospace;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.5;
|
|
||||||
background-color: var(--vscode-editor-background);
|
|
||||||
color: var(--vscode-editor-foreground);
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
margin: 0;
|
|
||||||
background-color: transparent !important;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
code {
|
|
||||||
font-family: 'Consolas', 'Courier New', monospace;
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
.hljs {
|
|
||||||
background-color: transparent;
|
|
||||||
color: var(--vscode-editor-foreground);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<pre><code class="language-c" id="code-content">${escapedContent}</code></pre>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/c.min.js"></script>
|
|
||||||
<script>
|
|
||||||
hljs.highlightAll();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deactivate(): Thenable<void> | undefined {
|
export function deactivate(): Thenable<void> | undefined {
|
||||||
if (!client) {
|
if (!client) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
Reference in New Issue
Block a user