How do I make multiline hilighter on draft-js? - draftjs

Now I make markdown highlighter.
Highlight inline is not so difficult. I use CompositeDecorator to rewrite text. https://facebook.github.io/draft-js/docs/advanced-topics-decorators.html
But I can't use multiline syntax (for example, codeblock). By default, newline becomes next block and decorator is handled by block to block.
Below image is example of my implementation. I can't decorate codeblock syntax.
How do I make multiline highlighter on draft-js?

Depends on what 'Highlight' style you want. Mostly the inline style should be enough if you just want some color or font size. check the color example.
While for block style, you need a custom CSS class and map the block to your class, refer this.

I found work around. Detecting markdown codeblock by dand on blockRendererFn.
// use blockRedererFn
<Editor
blockRendererFn={(block) => blockRenderer(block, this.state.editorState)}
editorState={this.state.editorState}
/>;
// detect code block and add fontFamily: monospace
// Example
//
// ```
// here
// ```
function blockRenderer(contentBlock, editorState) {
const type = contentBlock.getType();
if (type === "unstyled") {
const allText = editorState.getCurrentContent().getPlainText();
const allCount = countCodeBlockHeader(allText);
if (allCount > 0 && allCount % 2 === 0) {
const contentText = contentBlock.getText();
const [before, after] = allText.split(contentText);
const beforeCount = countCodeBlockHeader(before);
const afterCount = countCodeBlockHeader(after);
if (beforeCount % 2 === 1) {
if (afterCount % 2 === 1) {
return {
component: (_props) => {
return <code style={{
fontFamily: "monospace",
direction: "ltr",
unicodeBidi: "bidi-override",
}}>{contentText}</code>;
},
editable: true
};
}
}
}
}
}
function countCodeBlockHeader(text) {
return text
.split("\n")
.filter(l => l.match(new RegExp("^(```)")))
.length;
}
but it's dirty.

Related

Use Hogan template inside instantsearch widget connector

I have used Hogan templates in widgets, and now I want to use it inside a widget connector. Does anyone know how to do that?
All docs on instantsearch only uses javascript template literals.
Example:
const fmInfiniteHits = instantsearch.connectors.connectInfiniteHits(
(renderArgs, isFirstRender) => {
const { hits, showMore, widgetParams } = renderArgs;
const { container } = widgetParams;
if (isFirstRender) {
$(container).append('<ul></ul>');
return;
}
// NOW
$(container +' ul').html(hits.map(hit => `<li> ... </li>`));
// WHAT I WANT
let result = hits.renderWithHogan; // <-- How do I do this
$(container +' ul').html(result);
},
);

the function ToHaveStyleRule doesn't work with hover

I created a component to be an Icons wrapper, so I don't need to keep editing the icon in the style of the file I use... However, when testing a property that can be applied to the "hover" component , the test says that this property does not exist, even passing!
file index
export type IconsProps = {
hoverColor?: colorTypes
}
const Icons = ({ hoverColor }: IconsProps) => (
<S.Wrapper color={color} size={size} hoverColor={hoverColor}>
{children}
</S.Wrapper>
)
file style
const wrapperModifiers = {
hoverColor: (theme: DefaultTheme, hoverColor: colorTypes) => css`
& :hover {
color: ${theme.colors[hoverColor]};
}
`,
}
export const Wrapper = styled.main<IconsProps>`
${({ theme, hoverColor }) => css`
> ${StyledIconBase} {
${!!hoverColor && wrapperModifiers.hoverColor(theme, hoverColor)}
}
`}
`
test
import { Coffee } from '#styled-icons/boxicons-solid'
it('deve testar o hover e o transform', () => {
const { debug, container } = renderWithTheme(
<Icons color="primary" size="5rem" hoverColor="secondary">
<Coffee title="Coffee" />
</Icons>,
)
expect(screen.getByRole('img', { name: /coffee/i })).toHaveStyleRule(
'color',
'#0487cc',
{
modifier: ':hover',
},
)
})
error
No style rules found on passed Component using options:
{"modifier":":hover"}
In my opinion, the error that you are getting is that you haven't properly selected the element which is having a hover color. Because of that reason, jest-styled-component is not able to find the element with a hover modifier.
& :hover {
color: ${theme.colors[hoverColor]};
}
You added a space between & and : which is not right. The hover will not be applied to the selected element.
Solution: Remove the space between them.
&:hover {
color: ${theme.colors[hoverColor]};
}

What is the name of the element that github copilot uses to highlighting text?

I would like to make a control similar to the used by github copilot. I mean highlighting the proposed text. Live share extension uses a very similar approach. What is the name of this control?
Control in live preview extension:
Control in copilot extension:
I guess it could be TextEditorDecorationType? However, I do not know how to style it so that the author is absolutely positioned :/
You can create a similar experience using Text Editor Decorators. These decorators allow you to use custom style patterns for any text in a document (including foreground and background colors).
The text highlighting examples that you have visualized above, are simply adding a a background color to a span of text that has been selected by a user, or suggested by an extension.
As an example: if you wanted to add custom highlighting for console.log:
Then you could use the following:
import * as vscode from 'vscode'
const decorationType = vscode.window.createTextEditorDecorationType({
backgroundColor: 'green',
border: '2px solid white',
})
export function activate(context: vscode.ExtensionContext) {
vscode.workspace.onWillSaveTextDocument(event => {
const openEditor = vscode.window.visibleTextEditors.filter(
editor => editor.document.uri === event.document.uri
)[0]
decorate(openEditor)
})
}
function decorate(editor: vscode.TextEditor) {
let sourceCode = editor.document.getText()
let regex = /(console\.log)/
let decorationsArray: vscode.DecorationOptions[] = []
const sourceCodeArr = sourceCode.split('\n')
for (let line = 0; line < sourceCodeArr.length; line++) {
let match = sourceCodeArr[line].match(regex)
if (match !== null && match.index !== undefined) {
let range = new vscode.Range(
new vscode.Position(line, match.index),
new vscode.Position(line, match.index + match[1].length)
)
let decoration = { range }
decorationsArray.push(decoration)
}
}
editor.setDecorations(decorationType, decorationsArray)
}
Reference Link

Unable to pass parameter from command to converter

I'm trying to edit the actual existing plugin of highlight to be able to add text color customizable from command argument, which means that if you put RGB or hex color it will take it on the selection create a view attribute style = 'color: PARAMETER'
What I got so far just surround the text with font tag and the style attribute with color but with a color value incorrect.
Which mean the value on the command is not being passed to the converter.
I'm being unable to find a way to transfer input information from a command to use directly in the converter to make this feature works.
The normal behavior in this plugin make it impossible to use the 16 million colors from RGB, and it requires an obsolete model of defined colors.
You can see/edit/use what i've done so far in this repo
https://github.com/klys/ckeditor5-highlight-inline
In this part the converter create the font element with the style color but with a incorrect value for color value.
editor.conversion.attributeToElement( {
model: HIGHLIGHT,
view: {
name: 'font',
styles: {
'color': true
},
priority: 5,
model: {
key: 'highlight',
value: viewElement => viewElement.getAttribute( 'color' )
},
type:'pen'
}
} );
And this the edited command executor from the original plugin, which i edit to meet the needs of this feature.
execute( color ) {
const model = this.editor.model;
const document = model.document;
const selection = document.selection;
//const highlighter = options.value;
/*var __model;
for ( const option of options ) {
__model = new Model( {
model: 'color model',
class: 'color-class',
title: 'color pen',
color: option.value,
type: 'pen'
} );
}
const highlighter = __model;*/
model.change( writer => {
const ranges = model.schema.getValidRanges( selection.getRanges(), 'highlight' );
if ( selection.isCollapsed ) {
const position = selection.getFirstPosition();
// When selection is inside text with `highlight` attribute.
if ( selection.hasAttribute( 'highlight' ) ) {
// Find the full highlighted range.
const isSameHighlight = value => {
return value.item.hasAttribute( 'highlight' ) && value.item.getAttribute( 'highlight' ) === this.value;
};
const highlightStart = position.getLastMatchingPosition( isSameHighlight, { direction: 'backward' } );
const highlightEnd = position.getLastMatchingPosition( isSameHighlight );
const highlightRange = writer.createRange( highlightStart, highlightEnd );
// Then depending on current value...
if ( !color || this.value === color ) {
// ...remove attribute when passing highlighter different then current or executing "eraser".
writer.removeAttribute( 'highlight', highlightRange );
writer.removeSelectionAttribute( 'highlight' );
} else {
// ...update `highlight` value.
writer.setAttribute( 'highlight', color, highlightRange );
writer.setSelectionAttribute( 'highlight', color );
}
} else if ( color ) {
writer.setSelectionAttribute( 'highlight', color );
}
} else {
for ( const range of ranges ) {
if ( color ) {
writer.setAttribute( 'highlight', color, range );
} else {
writer.removeAttribute( 'highlight', range );
}
}
}
} );
}
I have been almost a week in this problem.
If you can a least point me out in the right direction, you won't imagine how much you will help me.

Is it possible to set TextDocument as dirty programatically in VSCode?

Is it possible to set a TextDocument as dirty programatically in VSCode? Something like
openedDocument.setDirty()
There isn't a direct way to do it; TextDocument.isDirty is a read-only property.
However, I put together a workaround that sets isDirty by making an edit that has no effect (tested with VSCode 1.37.1):
// Set the dirty bit on 'textEditor'. This is meant to be called as a
// text editor command.
async function setDirty(textEditor: TextEditor, editBuilder: TextEditorEdit)
: Promise<void>
{
// The strategy here is to make a change that has no effect. If the
// document has text in it, we can replace some text with itself
// (simply inserting an empty string does not work). We prefer to
// edit text at the end of the file in order to minimize spurious
// recomputation by analyzers.
// Try to replace the last line.
if (textEditor.document.lineCount >= 2) {
const lineNumber = textEditor.document.lineCount-2;
const lastLineRange = new Range(
new Position(lineNumber, 0),
new Position(lineNumber+1, 0));
const lastLineText = textEditor.document.getText(lastLineRange);
editBuilder.replace(lastLineRange, lastLineText);
return;
}
// Try to replace the first character.
const range = new Range(new Position(0, 0), new Position(0, 1));
const text = textEditor.document.getText(range);
if (text.length > 0) {
editBuilder.replace(range, text);
return;
}
// With an empty file, we first add a character and then remove it.
// This has to be done as two edits, which can cause the cursor to
// visibly move and then return, but we can at least combine them
// into a single undo step.
await textEditor.edit(
(innerEditBuilder: TextEditorEdit) => {
innerEditBuilder.replace(range, " ");
},
{ undoStopBefore: true, undoStopAfter: false });
await textEditor.edit(
(innerEditBuilder: TextEditorEdit) => {
innerEditBuilder.replace(range, "");
},
{ undoStopBefore: false, undoStopAfter: true });
}
In your activate function, hook it up with something like:
context.subscriptions.push(
commands.registerTextEditorCommand("extension.setDirty", setDirty));