I am building an ad-hoc text-editor. I have two functions which use a cache, provideHover
and provideCompletionItems
.
"use strict";
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
const $ = require("jquery");
const urlResolve = require("url-resolve");
const AUTOCOMPLETE_ENDPOINT = "http://localhost:7000/";
const LRU = require("lru-cache");
const options = {
max: 500,
length: (suggestions, key) => { return suggestions.length }
};
const cache = new LRU(options);
const definition_cache = new LRU(options);
(function () {
// create div to avoid needing a HtmlWebpackPlugin template
const div = document.createElement('div');
div.id = 'root';
div.style = 'width:800px; height:600px; border:1px solid #ccc;';
document.body.appendChild(div);
})();
monaco.editor.create(
document.getElementById('root'),
{
value: ``,
language: 'python',
theme: 'vs-dark'
}
);
const getCompletions = (text) => {
return $.ajax({
url: urlResolve(AUTOCOMPLETE_ENDPOINT, "suggestion"),
type: 'GET',
"data": {
"text": text
}
});
};
const getDocumentation = (cursorInfo) => {
const line = cursorInfo.line;
const column = cursorInfo.column;
const text = cursorInfo.text;
return $.ajax({
url: urlResolve(AUTOCOMPLETE_ENDPOINT, "documentation"),
type: 'GET',
"data": {
"line": line,
"column": column,
"text": text,
"highlighted": cursorInfo.highlighted
}
});
}
monaco.languages.registerHoverProvider("python", {
provideHover: async (model, position) => {
const lineNumber = position.lineNumber;
const snippet = model.getWordAtPosition(position);
const text = model.getValueInRange({ startLineNumber: 1, startColumn: 1, endLineNumber: position.lineNumber, endColumn: snippet.endColumn });
if (definition_cache.has(text)) {
console.log("hit");
return {
contents: [{ value: definition_cache.get(text) }]
}
}
const response = await getDocumentation({ "line": lineNumber, "column": snippet.endColumn, "text": text, "highlighted": snippet.word });
definition_cache.set(text, response.documentation);
return {
contents: [{ value: response.documentation }]
}
}
});
monaco.languages.registerCompletionItemProvider('python', {
provideCompletionItems: async (model, position) => {
const text = model.getValueInRange({ startLineNumber: 1, startColumn: 1, endLineNumber: position.lineNumber, endColumn: position.column });
if (cache.has(text)) {
const suggestions = cache.get(text);
return {
"suggestions": suggestions
};
}
const completions = await getCompletions(text)
const suggestions = completions.map(c => ({
label: c.name,
insertText: c.name
}));
cache.set(text, suggestions)
return {
"suggestions": suggestions
};
}
});
As it stands, the introduction of the cache makes the code quite ugly (in my opinion). I'd like to refactor it so that I have only one cache usage that applies in both situations -- something like a Python decorator.
How do I make the code cleaner?
1 Answer 1
I'd look at python decorators as something, that accepts function and returns function, which is usually original function wrapped in another function and some added behaviour.
Change signature of your "decorator" functions to match that and you got something like decorators. Don't have much time at the moment to write examples, but you get the idea :-)
Edit: I took a closer look at your code, but it seems very specific to your framework and I can't make complete sense of it to dare refactoring (doesn't mean it's bad code). At least here are some examples of wrapper functions to help you started: https://gist.github.com/harrylove/1230566/d064e5c216384d3846f73ed555e9899be02e8f98