sloops
April 29, 2021, 7:25am
#1
Just starting out with CodeMirror6, I’m building a Markdown-Editor and want to add basic Markdown KeyMaps, starting with marking a selection as Bold. I got the first part down, but want it to behave like a toggle, so when a selection is already wrapped in **
, eg. due to a previous Mod+b
, I want to remove the **
.
This is what I have so far.
const insertBoldMarker: StateCommand = ({ state, dispatch }) => {
const changes = state.changeByRange((range) => {
return {
changes: [
{
from: range.from,
insert: Text.of(['**']),
},
{
from: range.to,
insert: Text.of(['**']),
},
],
range: EditorSelection.range(range.from + 2, range.to + 2),
}
})
dispatch(
state.update(changes, {
scrollIntoView: true,
annotations: Transaction.userEvent.of('input'),
})
)
return true
}
const customKeyMap: KeyBinding[] = [
{
key: 'Mod-b',
run: insertBoldMarker,
},
]
How would I check whether eg (range.from - 2)
are "**"
? Especially keeping possible Multiselection (not yet enabled) in mind.
I just need some directions
Update : probably with iterRange
, gonna look into that!
1 Like
marijn
April 29, 2021, 9:08am
#2
I think just doing state.sliceDoc(range.from - 2, range.from) == "**"
should work here.
1 Like
sloops
April 29, 2021, 11:47am
#3
Of course! I got it to work the way I want.
Really digging the API design of CM6! Thank you so much doing this! For anyone else who might land here via google, this is my result:
const insertBoldMarker: StateCommand = ({ state, dispatch }) => {
const changes = state.changeByRange((range) => {
const isBoldBefore = state.sliceDoc(range.from - 2, range.from) === "**";
const isBoldAfter = state.sliceDoc(range.to, range.to + 2) === "**";
const changes = [];
changes.push(isBoldBefore ? {
from: range.from - 2,
to: range.from,
insert: Text.of([''])
} : {
from: range.from,
insert: Text.of(['**']),
})
changes.push(isBoldAfter ? {
from: range.to,
to: range.to + 2,
insert: Text.of([''])
} : {
from: range.to,
insert: Text.of(['**']),
})
const extendBefore = isBoldBefore ? -2 : 2;
const extendAfter = isBoldAfter ? -2 : 2;
return {
changes,
range: EditorSelection.range(range.from + extendBefore, range.to + extendAfter),
}
})
dispatch(
state.update(changes, {
scrollIntoView: true,
annotations: Transaction.userEvent.of('input'),
})
)
return true
}
const boldBinding: KeyBinding[] = [
{
key: 'Mod-b',
run: insertBoldMarker,
},
]
3 Likes
ylc395
May 10, 2021, 12:53pm
#4
Hello, I’m trying to make a markdown editor, too. Thanks for your example code, and there are still two questions bothering me:
what is the annotations: Transaction.userEvent.of('input')
for?
I’m trying to use EditorSelection.range(range.from, range.to + 4)
to make marked-by-*-text selected, but it fail like this
BTW, EditorSelection.range(range.from + 2, range.to + 2)
worked as expected.
marijn
May 10, 2021, 1:10pm
#5
That marks a transaction as being user text input (which causes some extensions, such as autocompletion, to react differently).
Not sure what’s happening there.
ylc395
May 10, 2021, 1:14pm
#6
Can It be reproduced, or it’s just my wrong usage in CM6?
marijn
May 10, 2021, 2:24pm
#7
I’m not sure how exactly you’re using that expression. A small, self-contained example might help.