From 685ae59a05ef3fb8b550b47c726ffdb96510e988 Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Tue, 11 Mar 2025 11:58:56 -0400 Subject: [PATCH 1/5] fix off by one error, add text for partial selection --- src/commonmark/commands.ts | 52 ++++++++++++++------------------ test/commonmark/commands.test.ts | 16 ++++++++++ 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/commonmark/commands.ts b/src/commonmark/commands.ts index 7f481756..0ccdbb0e 100644 --- a/src/commonmark/commands.ts +++ b/src/commonmark/commands.ts @@ -416,57 +416,49 @@ function blockWrapIn( const newlineOffset = 2; // account for two inserted newlines return insertRawText( insertedBlock, - formattingText.length + newlineOffset, + formattingText.length + newlineOffset, //only selects the placeholder text, not the formattingText formattingText.length + placeholderText.length + newlineOffset, state, dispatch ); } - let { from, to } = state.selection; + const from = state.selection.from; + let to = state.selection.to; - // check if we need to unwrap - if (blockUnwrapIn(formattingText, state, dispatch)) { - return true; - } // wrap the selected block in code fences, prepending/appending newlines if necessary - let tr = state.tr; - // if the character immediately preceding the selection isn't a newline, add one - if (from > 0 && state.doc.textBetween(from - 1, from) !== "\n") { - tr = tr.insertText("\n", from, from); - from += 1; - to += 1; - } - // if the character immediately postceding the selection isn't a newline, add one - if ( - to + 1 < state.doc.content.size && - state.doc.textBetween(to, to + 1) !== "\n" - ) { - tr = tr.insertText("\n", to + 1, to + 1); - to += 1; - } + let tr = state.tr; - // add this char before and after the selection along with the formatting text const surroundingChar = "\n"; + //always insert a newline before the selection + tr = tr.insertText(surroundingChar, from, from); + to += 1; + + //always insert a newline after the selection + tr = tr.insertText(surroundingChar, to, to); + to += 1; + // insert the code fences from the end first so we don't mess up our from index - tr.insertText(surroundingChar + formattingText, to); - tr.insertText(formattingText + surroundingChar, from); + //consider if we need to add the surrounding char too, if the text is not already surrounded by newline + + const preceedingNewlineNeeded = from > 0 && state.doc.textBetween(from - 1, from) !== surroundingChar ? surroundingChar : ''; + const followingNewlineNeeded = to + 1 < state.doc.content.size && state.doc.textBetween(to, to + 1) !== surroundingChar ? surroundingChar : ''; + tr.insertText(formattingText + followingNewlineNeeded, to); + tr.insertText(preceedingNewlineNeeded + formattingText, from); + to += (formattingText.length * 2) + preceedingNewlineNeeded.length; + // set the selection to the text inside the code fences, skipping the leading newline if (dispatch) { - // adjust our new text selection based on how many characters we added - const addedTextModifier = - surroundingChar.length + formattingText.length; tr.setSelection( TextSelection.create( state.apply(tr).doc, - from, - // add modifier twice, once for added leading text, once for added trailing text - to + addedTextModifier * 2 + from + preceedingNewlineNeeded.length, + to ) ); diff --git a/test/commonmark/commands.test.ts b/test/commonmark/commands.test.ts index 903d57fb..1362ca90 100644 --- a/test/commonmark/commands.test.ts +++ b/test/commonmark/commands.test.ts @@ -220,6 +220,22 @@ some text ); }); + it("should wrap partial selection in block characters", () => { + const content = "some text"; + const expectedSelection = `\`\`\` +some +\`\`\``; + const expectedContent = "\n" + expectedSelection + "\n" + " text"; + + const state = createState(content, 0, 4); + + expect(state).transactionSuccess( + commands.blockWrapInCommand("```"), + expectedContent, + expectedSelection + ); + }); + it("should unwrap block", () => { const content = `\`\`\` some text From 8aa711ed7148317de22077e2d1ee33fc4c75d1ff Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Tue, 11 Mar 2025 12:12:28 -0400 Subject: [PATCH 2/5] fix code style? --- src/commonmark/commands.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/commonmark/commands.ts b/src/commonmark/commands.ts index 0ccdbb0e..915b0666 100644 --- a/src/commonmark/commands.ts +++ b/src/commonmark/commands.ts @@ -439,8 +439,8 @@ function blockWrapIn( to += 1; //always insert a newline after the selection - tr = tr.insertText(surroundingChar, to, to); - to += 1; + tr = tr.insertText(surroundingChar, to, to); + to += 1; // insert the code fences from the end first so we don't mess up our from index //consider if we need to add the surrounding char too, if the text is not already surrounded by newline @@ -453,7 +453,6 @@ function blockWrapIn( // set the selection to the text inside the code fences, skipping the leading newline if (dispatch) { - tr.setSelection( TextSelection.create( state.apply(tr).doc, From 8aba6609e940f5733327c03e21e46763d5ba6474 Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Tue, 11 Mar 2025 12:16:21 -0400 Subject: [PATCH 3/5] clean up extra newlines --- src/commonmark/commands.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/commonmark/commands.ts b/src/commonmark/commands.ts index 915b0666..e0db607c 100644 --- a/src/commonmark/commands.ts +++ b/src/commonmark/commands.ts @@ -426,10 +426,8 @@ function blockWrapIn( const from = state.selection.from; let to = state.selection.to; - // wrap the selected block in code fences, prepending/appending newlines if necessary - let tr = state.tr; const surroundingChar = "\n"; @@ -447,6 +445,7 @@ function blockWrapIn( const preceedingNewlineNeeded = from > 0 && state.doc.textBetween(from - 1, from) !== surroundingChar ? surroundingChar : ''; const followingNewlineNeeded = to + 1 < state.doc.content.size && state.doc.textBetween(to, to + 1) !== surroundingChar ? surroundingChar : ''; + tr.insertText(formattingText + followingNewlineNeeded, to); tr.insertText(preceedingNewlineNeeded + formattingText, from); to += (formattingText.length * 2) + preceedingNewlineNeeded.length; From b53b1a5219782dfcf4210f1204fd7ad0c46097c1 Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Wed, 12 Mar 2025 13:18:25 -0400 Subject: [PATCH 4/5] check for dispatch --- src/commonmark/commands.ts | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/commonmark/commands.ts b/src/commonmark/commands.ts index e0db607c..550e461e 100644 --- a/src/commonmark/commands.ts +++ b/src/commonmark/commands.ts @@ -423,6 +423,8 @@ function blockWrapIn( ); } + if (!dispatch) return true; + const from = state.selection.from; let to = state.selection.to; @@ -436,10 +438,10 @@ function blockWrapIn( tr = tr.insertText(surroundingChar, from, from); to += 1; - //always insert a newline after the selection + //always insert a newline after the selection tr = tr.insertText(surroundingChar, to, to); to += 1; - + // insert the code fences from the end first so we don't mess up our from index //consider if we need to add the surrounding char too, if the text is not already surrounded by newline @@ -451,19 +453,18 @@ function blockWrapIn( to += (formattingText.length * 2) + preceedingNewlineNeeded.length; // set the selection to the text inside the code fences, skipping the leading newline - if (dispatch) { - tr.setSelection( - TextSelection.create( - state.apply(tr).doc, - from + preceedingNewlineNeeded.length, - to - ) - ); - tr.scrollIntoView(); + tr.setSelection( + TextSelection.create( + state.apply(tr).doc, + from + preceedingNewlineNeeded.length, + to + ) + ); - dispatch(tr); - } + tr.scrollIntoView(); + + dispatch(tr); return true; } From 7fc27016e79e37af6724eccb16e5ff1038733fa7 Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Wed, 12 Mar 2025 13:19:56 -0400 Subject: [PATCH 5/5] format code --- src/commonmark/commands.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/commonmark/commands.ts b/src/commonmark/commands.ts index 550e461e..7b190102 100644 --- a/src/commonmark/commands.ts +++ b/src/commonmark/commands.ts @@ -445,12 +445,19 @@ function blockWrapIn( // insert the code fences from the end first so we don't mess up our from index //consider if we need to add the surrounding char too, if the text is not already surrounded by newline - const preceedingNewlineNeeded = from > 0 && state.doc.textBetween(from - 1, from) !== surroundingChar ? surroundingChar : ''; - const followingNewlineNeeded = to + 1 < state.doc.content.size && state.doc.textBetween(to, to + 1) !== surroundingChar ? surroundingChar : ''; + const preceedingNewlineNeeded = + from > 0 && state.doc.textBetween(from - 1, from) !== surroundingChar + ? surroundingChar + : ""; + const followingNewlineNeeded = + to + 1 < state.doc.content.size && + state.doc.textBetween(to, to + 1) !== surroundingChar + ? surroundingChar + : ""; tr.insertText(formattingText + followingNewlineNeeded, to); tr.insertText(preceedingNewlineNeeded + formattingText, from); - to += (formattingText.length * 2) + preceedingNewlineNeeded.length; + to += formattingText.length * 2 + preceedingNewlineNeeded.length; // set the selection to the text inside the code fences, skipping the leading newline