Ionaru / easy-markdown-editor

EasyMDE: A simple, beautiful, and embeddable JavaScript Markdown editor. Delightful editing for beginners and experts alike. Features built-in autosaving and spell checking.
https://stackblitz.com/edit/easymde
MIT License
2.45k stars 319 forks source link

Autocomplete for links - CodeMirror Addons #149

Open eklam opened 4 years ago

eklam commented 4 years ago

How to implemet autocomplete using CodeMirror Addons?

I want to implement an autocomplete feature, so when the user starts typing a link, the editor would suggest from a predefined list of options.

Exploring CodeMirror I found this autocomplete example that uses addons.

I could find on the easymde docs how to add addons to the underlying CodeMirror instance. Would I have to change easymde code? If so, is it just a matter of passing the addons in the easymde options and the pass those when initializing CodeMirror?

andreimoment commented 4 years ago

@eklam did you find a way to add autocomplete to easymde?

eklam commented 4 years ago

Yes.. I'm using it with React, so you may need to adjust the code a bit:

import CodeMirror, { HintFunction, Hints } from 'codemirror'
import 'codemirror/addon/hint/show-hint'
import 'codemirror/addon/hint/show-hint.css'
import EasyMDE, { ToolbarIcon } from 'easymde'
import 'easymde/dist/easymde.min.css'

...

function getHinter(your-entities-here): HintFunction {
    const suggestionList = your-custom-list-here
    return function hintFunction(cm: CodeMirror.Editor): Hints {
        const cur = cm.getCursor()
        const token = cm.getTokenAt(cur)
        const { start, end } = token

        const from = CodeMirror.Pos(cur.line, start)
        const to = CodeMirror.Pos(cur.line, end)

        const allResults = { from, to, list: suggestionList.map((s) => s.path) }

        const currentLine = cm.getRange({ line: from.line, ch: 0 }, to)

        const lastSeparatedWord = /\b(\w+)$/g
        const allMatches = [...currentLine.matchAll(lastSeparatedWord)]

        if (!allMatches.length) {
            return allResults
        }

        const matchedWord = allMatches[0]
        const word = matchedWord[0]

        if (!word) {
            return allResults
        }

        const suggestions = filter-or-change-your-suggestion-list-here

        return {
            from: {
                // Current line
                line: from.line,

                // Position of the matched
                ch: matchedWord.index !== undefined ? matchedWord.index : from.ch,
            },
            to,
            list: suggestions,
        }
    }
}

...

// When creating a toolbar:
    ....
   {
        name: `autocomplete`,
        action: (editor: EasyMDE) => CodeMirror.showHint(
            editor.codemirror,
            getHinter(your-parameters),
        ),
        title: 'Autocomplete',
    }
    ....
rathboma commented 2 years ago

This code doesn't work for me because it still expects editor.codemirror to contain the showHint function, which it doesn't.

Can you paste more code about how you initialize this?

eklam commented 2 years ago

There's too many files involved and tied to my custom app logic for me to copy and paste.

But I think what you need to do is install the CodeMirror package directly and import the show-hint plugin:

import 'codemirror/addon/hint/show-hint.css' import 'codemirror/addon/hint/show-hint'