uiwjs / react-codemirror

CodeMirror 6 component for React. @codemirror https://uiwjs.github.io/react-codemirror/
https://uiwjs.github.io/react-codemirror/
MIT License
1.65k stars 132 forks source link

Custom hyperlinks question #525

Open guillermoamaral opened 1 year ago

guillermoamaral commented 1 year ago

Is there any way to use @uiw/codemirror-extensions-hyper-link but with any arbitrary text instead of an URL (customizing the click even handling) and without using markdown?

For instance, lets supose I have a code editor where I show user code, and the conde contains a global MyClass, and I want to let the user to "browse" this global by means of a link:

new MyClass();

so when users clicks on MyClass, they are guided to the definition of such global.

Thanks!

jaywcjlove commented 1 year ago

@guillermoamaral Upgrade v4.21.4

Custom match content

import { EditorView } from '@codemirror/view';
import { EditorState } from '@codemirror/state';
import { hyperLinkExtension, hyperLinkStyle } from '@uiw/codemirror-extensions-hyper-link';

const code = `Hyper Link\n====`;

export const hyperLink: Extension = [
  hyperLinkExtension({
    regexp: /Hyper/gi,
    match: { Hyper: 'https://google.com' },
    handle: (value) => {
      if (value === 'Hyper') return 'https://google.com';
      return value;
    },
  }),
  hyperLinkStyle,
];

const state = EditorState.create({
  doc: code,
  extensions: [hyperLink],
});

const view = new EditorView({
  parent: document.querySelector('#editor'),
  state,
});
guillermoamaral commented 1 year ago

Nice! However, would it be possible to:

Thanks in advance!

jaywcjlove commented 1 year ago

@guillermoamaral Manipulating editor text, causing editing problems. A definition with a similar syntax may be required if you need to define URL text styles.

guillermoamaral commented 1 year ago

What about handling the click event? Isn't it possible to do something particular (instead of the default behavior)?

jaywcjlove commented 1 year ago

@guillermoamaral If I define an anchor option, I don't know if it can solve your problem.

hyperLinkExtension({
  regexp: /Hyper/gi,
  match: { Hyper: 'https://google.com' },
  handle: (value) => {
    if (value === 'Hyper') return 'https://google.com';
    return value;
  },
+  anchor: ($dom) => {
+    $dom.className = 'cm-hyper-link-icon';
+    return $dom
+  }
})
guillermoamaral commented 1 year ago

Would I be able to manage the click event in my app? I'm not sure if such option will allow me to do that.

jaywcjlove commented 1 year ago

@guillermoamaral Upgrade v4.21.5

guillermoamaral commented 1 year ago

Great! This really helped!

I'm struggling with the regex though as it matches things that I wouldn't like it to do.

I'm using /\b[A-Z].*?\b/g as regex. For instance, in the following example, the regex matches Answer in the comment but I know beforehand that that is not meant to be "linkable" (i.e., I can check easily that that, a) that is not a valid global, and b) it is inside a comment, so I would exclude it from the links if I had my way).

image

I will continue exploring alternatives anyway but if you could rather extend the specification of decorations (with something such as from and to positions), I would really appreciate it!.

Thanks!

jaywcjlove commented 1 year ago

@guillermoamaral You can list your desired api design

guillermoamaral commented 1 year ago

Ideally, it would be nice to able to specify the positions, start and to, of the hyperlinks texts, even when the to position was the one used to place the hyperlink icon as it is now (currently, both positions are determined internally by the MatchDecorator and passed as the arguments to the decorate callback). Probably this cannot be done as CodeMirror manages all this by its own.

Alternatively, it would be nice to have the chance to specify a callback to determine whether a piece matching the regex is actually a link. As I mentioned before, I know exactly what word can have a link as I have the list of globals.

Again, probalbly none of these can be done easily. In any case, thanks for your response.

jaywcjlove commented 1 year ago

@guillermoamaral

const hyperLink = [
  hyperLinkExtension({
    regexp: /codemirror/gi,
    match: { codemirror: 'https://google.com' },
-    handle: (value) => {
+    handle: (value, input, from, to) => {
      if (value === 'Hyper') return 'https://google.com';
      return value;
    },
  }),
  hyperLinkStyle,
];
guillermoamaral commented 1 year ago

Thanks!!!