diff --git a/CHANGELOG.md b/CHANGELOG.md index e4ed91fd..c1d672f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 0.3.2 - 2024-02-06 + +### ⚡️ Improve performance + +- Add "Visible" property to allow hiding the editor without destroying it + +### ✨ Introduce new features + +- Add linting that checks csv column count relative to first line +- Disable initial setting of line wrapping in csv mode + +### 🐛 Fix a bug + +- Fix tabulating csv columns skipped the last / first ones + +### 📝 Add or update documentation + +- Update README + ## 0.3.1 - 2024-02-06 ### 🐛 Fix a bug diff --git a/CodeMirror6/CodeMirror6.csproj b/CodeMirror6/CodeMirror6.csproj index 5c532505..3965b60b 100644 --- a/CodeMirror6/CodeMirror6.csproj +++ b/CodeMirror6/CodeMirror6.csproj @@ -9,7 +9,7 @@ GaelJ.BlazorCodeMirror6 true GaelJ.BlazorCodeMirror6 - 0.3.1 + 0.3.2 true snupkg true diff --git a/CodeMirror6/CodeMirror6Wrapper.razor b/CodeMirror6/CodeMirror6Wrapper.razor index 3b658636..4dc2a4bb 100644 --- a/CodeMirror6/CodeMirror6Wrapper.razor +++ b/CodeMirror6/CodeMirror6Wrapper.razor @@ -34,6 +34,7 @@ FileNameOrExtension="@FileNameOrExtension" HighlightWhitespace="@HighlightWhitespace" HighlightTrailingWhitespace="@HighlightTrailingWhitespace" + Visible="@Visible" /> diff --git a/CodeMirror6/CodeMirror6Wrapper.razor.cs b/CodeMirror6/CodeMirror6Wrapper.razor.cs index 094e190f..df14c68c 100644 --- a/CodeMirror6/CodeMirror6Wrapper.razor.cs +++ b/CodeMirror6/CodeMirror6Wrapper.razor.cs @@ -165,6 +165,11 @@ public partial class CodeMirror6Wrapper : ComponentBase /// [Parameter] public bool HighlightWhitespace { get; set; } /// + /// Whether the editor is visible + /// + /// + [Parameter] public bool Visible { get; set; } + /// /// Additional attributes to be applied to the container element /// /// diff --git a/CodeMirror6/CodeMirror6WrapperInternal.razor b/CodeMirror6/CodeMirror6WrapperInternal.razor index 53b4e71a..4ae0f0b7 100644 --- a/CodeMirror6/CodeMirror6WrapperInternal.razor +++ b/CodeMirror6/CodeMirror6WrapperInternal.razor @@ -5,7 +5,7 @@
@for (var i = 0; i < (Doc?.Split("\n").Length ?? 10); i++) { var randomWidth = new Random().Next(20, 80); @@ -14,7 +14,7 @@
} -
+
[Parameter] public bool HighlightWhitespace { get; set; } /// + /// Whether the editor is visible + /// + /// + [Parameter] public bool Visible { get; set; } + /// /// Additional attributes to be applied to the container element /// /// @@ -183,6 +188,7 @@ public partial class CodeMirror6WrapperInternal : ComponentBase, IAsyncDisposabl : AllowVerticalResize ? "vertical" : AllowHorizontalResize ? "horizontal" : "none"; + private string VisibleClass => Visible ? string.Empty : " d-none "; /// /// JavaScript interop instance diff --git a/CodeMirror6/NodeLib/src/CmColumns.ts b/CodeMirror6/NodeLib/src/CmColumns.ts index 2b571a05..1a6ad8e5 100644 --- a/CodeMirror6/NodeLib/src/CmColumns.ts +++ b/CodeMirror6/NodeLib/src/CmColumns.ts @@ -1,6 +1,7 @@ import { Decoration, ViewPlugin, EditorView, KeyBinding } from "@codemirror/view"; import { Extension, RangeSetBuilder, Transaction } from "@codemirror/state"; import { buildWidget } from "./lib/codemirror-kit"; +import { Diagnostic } from "@codemirror/lint"; function createColumnReplaceDecoration(content: string, from: number) { @@ -49,6 +50,11 @@ function getRelativeColumnOffset(text: string, separator: string, position: numb } else if (char === '\\') { escapeNext = true offset++ + } else if (char === '\n' && previous) { + previousColumnOffset = offset + offset++ + } else if (char === '\n' && i >= position) { + return offset } else if (char === separator && !inQuotes && previous) { previousColumnOffset = offset offset++ @@ -133,6 +139,35 @@ export const getColumnStylingKeymap = (separator: string): KeyBinding[] => [ }}, ] +export function getSeparator(languageName: string) { + if (languageName === "CSV") return ',' + if (languageName === "TSV") return '\t' + return null +} + +export async function columnLintSource(view: EditorView, separator: string): Promise { + try { + const code = view.state.doc.toString() + const data = parseCSV(code, separator) + const nbCols = data[0].length + const errors: Diagnostic[] = [] + for (let i = 1; i < data.length; i++) { + if (data[i].length !== nbCols && data[i].length !== 1) { + const message = `Expected ${nbCols} columns, found ${data[i].length}` + const from = view.state.doc.line(i + 1).from + const to = view.state.doc.line(i + 1).to + errors.push({ from, to, message, severity: 'error' }) + } + } + if (errors.length > 0) + console.log('Linter found:', errors) + return errors + } catch (error) { + console.error('Linter error:', error) + return + } +} + function moveCursor(view: EditorView, inc: number) { console.log("moveCursors") const { state } = view diff --git a/CodeMirror6/NodeLib/src/CmLint.ts b/CodeMirror6/NodeLib/src/CmLint.ts index 9c5d9454..6fa94631 100644 --- a/CodeMirror6/NodeLib/src/CmLint.ts +++ b/CodeMirror6/NodeLib/src/CmLint.ts @@ -9,7 +9,8 @@ export async function externalLintSource(view: EditorView, dotnetHelper: DotNet. try { const code = view.state.doc.toString() const errors: Diagnostic[] = await dotnetHelper.invokeMethodAsync("LintingRequestedFromJS", code) - console.log('Linter found:', errors) + if (errors.length > 0) + console.log('Linter found:', errors) return errors } catch (error) { console.error('Linter error:', error) diff --git a/CodeMirror6/NodeLib/src/index.ts b/CodeMirror6/NodeLib/src/index.ts index a8a82c89..c57e67b2 100644 --- a/CodeMirror6/NodeLib/src/index.ts +++ b/CodeMirror6/NodeLib/src/index.ts @@ -58,7 +58,7 @@ import { DotNet } from "@microsoft/dotnet-js-interop" import { markdownTableExtension } from "./CmMarkdownTable" import { dynamicDiagramsExtension } from "./CmDiagrams" import { hideMarksExtension } from "./CmHideMarkdownMarks" -import { getColumnStylingKeymap, columnStylingPlugin } from "./CmColumns" +import { getColumnStylingKeymap, columnStylingPlugin, columnLintSource, getSeparator } from "./CmColumns" /** * Initialize a new CodeMirror instance @@ -99,13 +99,17 @@ export async function initCodeMirror( CMInstances[id].emojiReplacerCompartment.of(replaceEmojiExtension(initialConfig.replaceEmojiCodes)), lastOperationWasUndo, indentationMarkers(), - CMInstances[id].lineWrappingCompartment.of(initialConfig.lineWrapping ? EditorView.lineWrapping : []), + CMInstances[id].lineWrappingCompartment.of(initialConfig.lineWrapping && initialConfig.languageName !== "CSV" && initialConfig.languageName !== "TSV" ? EditorView.lineWrapping : []), CMInstances[id].unifiedMergeViewCompartment.of(initialConfig.mergeViewConfiguration ? unifiedMergeView(initialConfig.mergeViewConfiguration) : []), CMInstances[id].highlightTrailingWhitespaceCompartment.of(initialConfig.highlightTrailingWhitespace ? highlightTrailingWhitespace() : []), CMInstances[id].highlightWhitespaceCompartment.of(initialConfig.highlightWhitespace ? highlightWhitespace() : []), CMInstances[id].columnsStylingCompartment.of( initialConfig.languageName === "CSV" || initialConfig.languageName === "TSV" - ? [columnStylingPlugin(initialConfig.languageName === "CSV" ? ',' : '\t'), keymap.of(getColumnStylingKeymap(initialConfig.languageName === "CSV" ? ',' : '\t'))] + ? [ + columnStylingPlugin(getSeparator(initialConfig.languageName)), + keymap.of(getColumnStylingKeymap(getSeparator(initialConfig.languageName))), + linter(async view => columnLintSource(view, getSeparator(initialConfig.languageName))), + ] : [] ), @@ -304,6 +308,7 @@ export async function setLanguage(id: string, languageName: string, fileNameOrEx const customKeyMap = getLanguageKeyMaps(languageName, fileNameOrExtension) if (languageName !== "CSV" && languageName !== "TSV") customKeyMap.push(indentWithTab) + const separator = getSeparator(languageName) CMInstances[id].view.dispatch({ effects: [ @@ -313,7 +318,11 @@ export async function setLanguage(id: string, languageName: string, fileNameOrEx CMInstances[id].markdownStylingCompartment.reconfigure(autoFormatMarkdownExtensions(id, languageName === 'Markdown')), CMInstances[id].columnsStylingCompartment.reconfigure( languageName === "CSV" || languageName === "TSV" - ? [columnStylingPlugin(languageName === "CSV" ? ',' : '\t'), keymap.of(getColumnStylingKeymap(languageName === "CSV" ? ',' : '\t'))] + ? [ + columnStylingPlugin(separator), + keymap.of(getColumnStylingKeymap(separator)), + linter(async view => columnLintSource(view, separator)), + ] : [] ), ] diff --git a/Examples.BlazorServer/Examples.BlazorServer.csproj b/Examples.BlazorServer/Examples.BlazorServer.csproj index d91094cd..2d69aa5a 100644 --- a/Examples.BlazorServer/Examples.BlazorServer.csproj +++ b/Examples.BlazorServer/Examples.BlazorServer.csproj @@ -4,7 +4,7 @@ enable false enable - 0.3.1 + 0.3.2 diff --git a/Examples.BlazorServerInteractive/Examples.BlazorServerInteractive.csproj b/Examples.BlazorServerInteractive/Examples.BlazorServerInteractive.csproj index 88b0667f..3a0b5eac 100644 --- a/Examples.BlazorServerInteractive/Examples.BlazorServerInteractive.csproj +++ b/Examples.BlazorServerInteractive/Examples.BlazorServerInteractive.csproj @@ -4,7 +4,7 @@ enable enable false - 0.3.1 + 0.3.2 diff --git a/Examples.BlazorWasm/Examples.BlazorWasm.csproj b/Examples.BlazorWasm/Examples.BlazorWasm.csproj index 75357825..c6c863cf 100644 --- a/Examples.BlazorWasm/Examples.BlazorWasm.csproj +++ b/Examples.BlazorWasm/Examples.BlazorWasm.csproj @@ -4,7 +4,7 @@ enable enable false - 0.3.1 + 0.3.2 diff --git a/Examples.Common/Examples.Common.csproj b/Examples.Common/Examples.Common.csproj index 218498f0..10364307 100644 --- a/Examples.Common/Examples.Common.csproj +++ b/Examples.Common/Examples.Common.csproj @@ -5,7 +5,7 @@ enable enable false - 0.3.1 + 0.3.2 diff --git a/NEW_CHANGELOG.md b/NEW_CHANGELOG.md index 349f9f37..05361261 100644 --- a/NEW_CHANGELOG.md +++ b/NEW_CHANGELOG.md @@ -1,7 +1,16 @@ +### ⚡️ Improve performance + +- Add "Visible" property to allow hiding the editor without destroying it + +### ✨ Introduce new features + +- Add linting that checks csv column count relative to first line +- Disable initial setting of line wrapping in csv mode + ### 🐛 Fix a bug -- Fix shift-tab in csv not working on last cell +- Fix tabulating csv columns skipped the last / first ones -### 🥅 Catch errors +### 📝 Add or update documentation -- Silence errors when DOM elements are no longer available in Diagrams (SVG) and file upload (main div) +- Update README diff --git a/README.md b/README.md index d2ace8b2..c801fc9c 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Visit the [live demo](https://gaelj.github.io/BlazorCodeMirror6/) to see the com - [x] support C# language - [x] update doc in dotnet either on text changes or on blur - [x] diff viewer +- [x] CSV mode: add column paddings for alignment, navigate columns with tab / shift-tab - [ ] search & replace toolbar button - [ ] toolbar with toolbar button template - [ ] support read-only paragraphs @@ -47,7 +48,6 @@ Visit the [live demo](https://gaelj.github.io/BlazorCodeMirror6/) to see the com - [ ] automatic translation - [ ] deleting a file link deletes the file from the server - [ ] button (visible when editor is hovered), to copy raw editor content to clipboard -- [ ] CSV mode ### Markdown specific