mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-09-28 04:32:58 +00:00
better make link, better makespan make div make space and make nsb
This commit is contained in:
@@ -31,8 +31,7 @@ export async function formatCSS(view) {
|
||||
//Prettier can't do it by default, this is crude but it works
|
||||
formatted = formatted.replace(
|
||||
/([^{]+)\{\s*\n\s*([^;\n]+:[^;\n]+;)\s*\n\s*\}(\s*)/g,
|
||||
(_, selector, decl, whitespace) =>
|
||||
`${selector} { ${decl.trim()} }${whitespace}`
|
||||
(_, selector, decl, whitespace)=>`${selector} { ${decl.trim()} }${whitespace}`
|
||||
);
|
||||
if(formatted === code) return true;
|
||||
|
||||
@@ -57,6 +56,13 @@ export async function formatCSS(view) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const forEachSelection = (view, fn) => {
|
||||
view.dispatch(view.state.changeByRange((range) => fn(view.state, range)));
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
const insertTab = (view)=>{
|
||||
// If any selection spans multiple lines, delegates to CodeMirror's indentMore
|
||||
// Otherwise inserts two spaces at each cursor/selection
|
||||
@@ -127,12 +133,12 @@ const wrapSelection = (prefix, suffix) => (view) => {
|
||||
{
|
||||
from : from,
|
||||
to : from + prefix.length,
|
||||
insert: ""
|
||||
insert : ''
|
||||
},
|
||||
{
|
||||
from : to - suffix.length,
|
||||
to : to,
|
||||
insert: ""
|
||||
insert : ''
|
||||
}
|
||||
],
|
||||
range : EditorSelection.range(
|
||||
@@ -150,7 +156,7 @@ const wrapSelection = (prefix, suffix) => (view) => {
|
||||
},
|
||||
range : EditorSelection.range(
|
||||
from,
|
||||
to + suffix.length*2
|
||||
to + suffix.length + prefix.length
|
||||
)
|
||||
};
|
||||
})
|
||||
@@ -159,85 +165,111 @@ const wrapSelection = (prefix, suffix) => (view) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
const makeNbsp = (view)=>{
|
||||
const { from } = view.state.selection.main;
|
||||
|
||||
const prev2 = from >= 2
|
||||
? view.state.doc.sliceString(from - 2, from)
|
||||
: '';
|
||||
const makeNbsp = (view) => forEachSelection(view, (state, range) => {
|
||||
const { from, to } = range;
|
||||
|
||||
const prev2 = from >= 2 ? state.doc.sliceString(from - 2, from) : '';
|
||||
const insert = (prev2 === ':>' || prev2 === '>>') ? '>' : ':>';
|
||||
|
||||
view.dispatch({
|
||||
changes : { from, to: from, insert },
|
||||
selection : { anchor: from + insert.length },
|
||||
return {
|
||||
changes : { from, to, insert },
|
||||
range : EditorSelection.cursor(from + insert.length)
|
||||
};
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const makeSpace = (view)=>{
|
||||
const { from, to } = view.state.selection.main;
|
||||
const selected = view.state.doc.sliceString(from, to);
|
||||
const makeSpace = (view) => forEachSelection(view, (state, range) => {
|
||||
const { from, to } = range;
|
||||
const selected = state.doc.sliceString(from, to);
|
||||
const match = selected.match(/^{{width:(\d+)% }}$/);
|
||||
let newText = '{{width:10% }}';
|
||||
|
||||
let insert = '{{width:10% }}';
|
||||
|
||||
if(match) {
|
||||
const percent = Math.min(parseInt(match[1], 10) + 10, 100);
|
||||
newText = `{{width:${percent}% }}`;
|
||||
insert = `{{width:${percent}% }}`;
|
||||
}
|
||||
view.dispatch({ changes: { from, to, insert: newText } });
|
||||
return true;
|
||||
};
|
||||
|
||||
const removeSpace = (view)=>{
|
||||
return {
|
||||
changes : { from, to, insert },
|
||||
range : EditorSelection.range(from, from + insert.length)
|
||||
};
|
||||
});
|
||||
|
||||
const removeSpace = (view) => forEachSelection(view, (state, range) => {
|
||||
const { from, to } = view.state.selection.main;
|
||||
const selected = view.state.doc.sliceString(from, to);
|
||||
const match = selected.match(/^{{width:(\d+)% }}$/);
|
||||
if(match) {
|
||||
const percent = parseInt(match[1], 10) - 10;
|
||||
const newText = percent > 0 ? `{{width:${percent}% }}` : '';
|
||||
view.dispatch({ changes: { from, to, insert: newText } });
|
||||
return{ changes: { from, to, insert: newText } };
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const makeSpan = (view)=>{
|
||||
const { from, to } = view.state.selection.main;
|
||||
const selected = view.state.doc.sliceString(from, to);
|
||||
const text = selected.startsWith('{{') && selected.endsWith('}}')
|
||||
? selected.slice(2, -2)
|
||||
: `{{${selected}}}`;
|
||||
view.dispatch({ changes: { from, to, insert: text } });
|
||||
return true;
|
||||
};
|
||||
|
||||
const makeDiv = (view)=>{
|
||||
const { from, to } = view.state.selection.main;
|
||||
const selected = view.state.doc.sliceString(from, to);
|
||||
const text = selected.startsWith('{{') && selected.endsWith('}}')
|
||||
? selected.slice(2, -2)
|
||||
: `{{\n${selected}\n}}`;
|
||||
view.dispatch({ changes: { from, to, insert: text } });
|
||||
return true;
|
||||
};
|
||||
|
||||
const makeComment = (view)=>{
|
||||
const { from, to } = view.state.selection.main;
|
||||
const selected = view.state.doc.sliceString(from, to);
|
||||
const isHtmlComment = selected.startsWith('<!--') && selected.endsWith('-->');
|
||||
const text = isHtmlComment
|
||||
? selected.slice(4, -3)
|
||||
: `<!-- ${selected} -->`;
|
||||
view.dispatch({ changes: { from, to, insert: text } });
|
||||
return true;
|
||||
};
|
||||
});
|
||||
|
||||
const makeLink = (view) => {
|
||||
const ranges = view.state.selection.ranges;
|
||||
|
||||
// Multiple selections: pair them as alt text + URL
|
||||
if (ranges.length > 1) {
|
||||
const changes = [];
|
||||
|
||||
for (let i = 0; i < ranges.length - 1; i += 2) {
|
||||
const alt = view.state.doc.sliceString(
|
||||
ranges[i].from,
|
||||
ranges[i].to
|
||||
).trim();
|
||||
|
||||
const url = view.state.doc.sliceString(
|
||||
ranges[i + 1].from,
|
||||
ranges[i + 1].to
|
||||
).trim();
|
||||
|
||||
changes.push({
|
||||
from: ranges[i].from,
|
||||
to: ranges[i + 1].to,
|
||||
insert: `[${alt}](${url})`
|
||||
});
|
||||
}
|
||||
|
||||
view.dispatch({ changes });
|
||||
return true;
|
||||
}
|
||||
|
||||
// Single selection: existing behavior
|
||||
const { from, to } = view.state.selection.main;
|
||||
const selected = view.state.doc.sliceString(from, to).trim();
|
||||
|
||||
const isLink = /^\[(.*)\]\((.*)\)$/.exec(selected);
|
||||
const text = isLink ? `${isLink[1]} ${isLink[2]}` : `[${selected || 'alt text'}](url)`;
|
||||
view.dispatch({ changes: { from, to, insert: text } });
|
||||
|
||||
let text;
|
||||
|
||||
if (isLink) {
|
||||
text = `${isLink[1]} ${isLink[2]}`;
|
||||
} else {
|
||||
const isUrl =
|
||||
/^(https?:\/\/|www\.)\S+$/i.test(selected) ||
|
||||
/^[a-z0-9-]+(\.[a-z0-9-]+)+([/?#]\S*)?$/i.test(selected);
|
||||
|
||||
if (isUrl) {
|
||||
const url = selected;
|
||||
const domain = url
|
||||
.replace(/^https?:\/\//i, '')
|
||||
.replace(/^www\./i, '')
|
||||
.split(/[/?#]/)[0];
|
||||
|
||||
const name = domain.split('.')[0];
|
||||
|
||||
text = `[${name}](${url})`;
|
||||
} else {
|
||||
text = `[${selected || 'alt text'}](url)`;
|
||||
}
|
||||
}
|
||||
|
||||
view.dispatch({
|
||||
changes: { from, to, insert: text }
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -326,9 +358,9 @@ export const markdownKeymap = Prec.highest(keymap.of([
|
||||
{ key: 'Mod-.', run: makeNbsp },
|
||||
{ key: 'Shift-Mod-.', run: makeSpace },
|
||||
{ key: 'Shift-Mod-,', run: removeSpace },
|
||||
{ key: 'Mod-m', run: makeSpan },
|
||||
{ key: 'Shift-Mod-m', run: makeDiv },
|
||||
{ key: 'Mod-/', run: makeComment },
|
||||
{ key: 'Mod-m', run: wrapSelection('{{', '}}') },
|
||||
{ key: 'Shift-Mod-m', run: wrapSelection('{{\n', '\n}}') },
|
||||
{ key: 'Mod-/', run: wrapSelection('<!-- ', ' -->') },
|
||||
{ key: 'Mod-k', run: makeLink },
|
||||
{ key: 'Mod-Shift-u', run: makeList('UL') },
|
||||
{ key: 'Mod-Shift-o', run: makeList('OL') },
|
||||
|
||||
Reference in New Issue
Block a user