Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions crates/squawk_wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ struct LintError {
range_end: usize,
// used for the linter tab
messages: Vec<String>,
fix: Option<Fix>,
}

#[derive(Serialize)]
struct Fix {
title: String,
edits: Vec<TextEdit>,
}

#[derive(Serialize)]
struct TextEdit {
start_line_number: u32,
start_column: u32,
end_line_number: u32,
end_column: u32,
text: String,
}

#[wasm_bindgen]
Expand Down Expand Up @@ -97,6 +113,7 @@ pub fn lint(text: String) -> Result<JsValue, Error> {
range_start: range_start.into(),
range_end: range_end.into(),
messages: vec![],
fix: None,
}
});

Expand All @@ -116,6 +133,36 @@ pub fn lint(text: String) -> Result<JsValue, Error> {
None => vec![],
};

let fix = x.fix.map(|fix| {
let edits = fix
.edits
.into_iter()
.filter_map(|edit| {
let start_pos = line_index.line_col(edit.text_range.start());
let end_pos = line_index.line_col(edit.text_range.end());
let start_wide = line_index
.to_wide(line_index::WideEncoding::Utf16, start_pos)
.unwrap();
let end_wide = line_index
.to_wide(line_index::WideEncoding::Utf16, end_pos)
.unwrap();

Some(TextEdit {
start_line_number: start_wide.line,
start_column: start_wide.col,
end_line_number: end_wide.line,
end_column: end_wide.col,
text: edit.text.unwrap_or_default(),
})
})
.collect();

Fix {
title: fix.title,
edits,
}
});

LintError {
code: x.code.to_string(),
range_start: x.text_range.start().into(),
Expand All @@ -128,6 +175,7 @@ pub fn lint(text: String) -> Result<JsValue, Error> {
start_column: start.col,
end_line_number: end.line,
end_column: end.col,
fix,
}
});

Expand Down
82 changes: 79 additions & 3 deletions playground/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useEffect, useLayoutEffect, useRef } from "react"
import * as monaco from "monaco-editor"
import { LintError, useDumpCst, useDumpTokens, useErrors } from "./squawk"
import { LintError, Fix, useDumpCst, useDumpTokens, useErrors } from "./squawk"
import {
compress,
compressToEncodedURIComponent,
Expand Down Expand Up @@ -231,14 +231,16 @@ function Editor({
onChange?: (_: string) => void
onSave?: (_: string) => void
settings: monaco.editor.IStandaloneEditorConstructionOptions
markers?: monaco.editor.IMarkerData[]
markers?: Marker[]
}) {
const onChangeRef = useRef<((_: string) => void) | undefined>(null)
const onSaveRef = useRef<((_: string) => void) | undefined>(null)
const divRef = useRef<HTMLDivElement>(null)
const autoFocusRef = useRef(autoFocus)
const settingsInitial = useRef(settings)
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>(null)
const fixesRef = useRef<Map<string, Fix>>(new Map())

// TODO: replace with useEventEffect
useEffect(() => {
onChangeRef.current = onChange
Expand All @@ -251,6 +253,16 @@ function Editor({
if (markers == null) {
return
}

const fixesMap = new Map<string, Fix>()
for (const marker of markers) {
if (marker.fix) {
const key = createMarkerKey(marker)
fixesMap.set(key, marker.fix)
}
}
fixesRef.current = fixesMap

const model = editorRef.current?.getModel()
if (model != null) {
monaco.editor.setModelMarkers(model, "squawk", markers)
Expand All @@ -269,7 +281,7 @@ function Editor({
onSaveRef.current?.(editor.getValue())
})
monaco.languages.register({ id: "rast" })
monaco.languages.setMonarchTokensProvider("rast", {
const tokenProvider = monaco.languages.setMonarchTokensProvider("rast", {
tokenizer: {
// via: https://github.com/rust-lang/rust-analyzer/blob/9691da7707ea7c50922fe1647b1c2af47934b9fa/editors/code/ra_syntax_tree.tmGrammar.json#L16C17-L16C17
root: [
Expand All @@ -284,6 +296,55 @@ function Editor({
],
},
})

const codeActionProvider = monaco.languages.registerCodeActionProvider(
"pgsql",
{
provideCodeActions: (model, _range, context) => {
const actions: monaco.languages.CodeAction[] = []
for (const marker of context.markers) {
if (marker.source === "squawk") {
const key = createMarkerKey(marker)
const fix = fixesRef.current.get(key)
if (fix) {
const edits = fix.edits.map(
(edit): monaco.languages.IWorkspaceTextEdit => {
return {
resource: model.uri,
versionId: model.getVersionId(),
textEdit: {
range: new monaco.Range(
edit.start_line_number + 1,
edit.start_column + 1,
edit.end_line_number + 1,
edit.end_column + 1,
),
text: edit.text,
},
}
},
)
actions.push({
title: fix.title,
diagnostics: [marker],
kind: "quickfix",
edit: {
edits,
},
isPreferred: true,
})
}
}
}

return {
actions,
dispose: () => {},
}
},
},
)

editor.onDidChangeModelContent(() => {
onChangeRef.current?.(editor.getValue())
})
Expand All @@ -293,7 +354,9 @@ function Editor({
editorRef.current = editor
return () => {
editorRef.current = null
codeActionProvider.dispose()
editor?.dispose()
tokenProvider.dispose()
}
}, [])
useEffect(() => {
Expand Down Expand Up @@ -330,6 +393,18 @@ type Marker = monaco.editor.IMarkerData & {
range_start: number
range_end: number
messages: string[]
fix?: Fix
}

function createMarkerKey(marker: {
startLineNumber: number
startColumn: number
endLineNumber: number
endColumn: number
message: string
}): string {
// TODO: probably a better way to do this
return `${marker.startLineNumber}:${marker.startColumn}:${marker.endLineNumber}:${marker.endColumn}:${marker.message}`
}

function SyntaxTreePanel({ text }: { text: string }) {
Expand Down Expand Up @@ -372,6 +447,7 @@ function useMarkers(text: string): Array<Marker> {
range_start: x.range_start,
range_end: x.range_end,
messages: x.messages,
fix: x.fix,
code: {
value: x.code,
target: monaco.Uri.parse(
Expand Down
14 changes: 14 additions & 0 deletions playground/src/squawk.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ import initWasm, {
lint as lint_,
} from "./pkg/squawk_wasm"

export type TextEdit = {
start_line_number: number
start_column: number
end_line_number: number
end_column: number
text: string
}

export type Fix = {
title: string
edits: TextEdit[]
}

export type LintError = {
code: string
message: string
Expand All @@ -16,6 +29,7 @@ export type LintError = {
range_start: number
range_end: number
messages: string[]
fix?: Fix
}

function lintWithTypes(text: string): Array<LintError> {
Expand Down
Loading