shahnevis-core
Version:
**Shahnevis Core** is a lightweight and flexible library for building custom code editors. It provides essential features like syntax highlighting, a minimap, multi-cursor support, line numbering, and plugin management. This library is framework-agnostic,
187 lines (166 loc) • 8.8 kB
JavaScript
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
/*
This file is part of Shahnevis Core.
Copyright (C) 2024 shahrooz saneidarani (github.com/shahroozD)
Shahnevis Core is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Shahnevis Core is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { updateSyntaxHighlighting } from "../core/highlighting.js";
import { languages } from "./languages.js";
var selectedIndex = -1;
var definedVariables = new Set(); // To store defined variables
var definedObjects = new Set(); // To store defined objects
// Function to extract variables and objects from the code
export function extractDefinedVarsAndObjects(code) {
var varRegex = /\b(let|const|var|function)\s+(\w+)/g;
var objRegex = /(\w+)\s*=\s*{/g;
var match;
// Clear the existing sets
definedVariables.clear();
definedObjects.clear();
// Add defined variables
while ((match = varRegex.exec(code)) !== null) {
definedVariables.add(match[2]);
}
// Add defined objects
while ((match = objRegex.exec(code)) !== null) {
definedObjects.add(match[1]);
}
}
// Function to handle arrow key navigation in the suggestion dropdown
function handleArrowDown(event, editor, suggestionDropdown, insertSuggestion, highlighter) {
var items = suggestionDropdown.querySelectorAll('.suggestion-item');
if (suggestionDropdown.style.display !== 'none' && items.length > 0) {
if (event.key === 'ArrowDown') {
event.preventDefault();
selectedIndex = (selectedIndex + 1) % items.length;
highlightSelected(items);
} else if (event.key === 'ArrowUp') {
event.preventDefault();
selectedIndex = (selectedIndex - 1 + items.length) % items.length;
highlightSelected(items);
} else if (event.key === 'Enter' && selectedIndex >= 0) {
event.preventDefault();
insertSuggestion(items[selectedIndex].innerText, editor, suggestionDropdown, highlighter);
}
}
}
// Function to highlight the currently selected suggestion item
function highlightSelected(items) {
items.forEach(function (item, index) {
if (index === selectedIndex) {
item.classList.add('selected');
} else {
item.classList.remove('selected');
}
});
}
// Function to show the suggestions dropdown
function showSuggestionsDropdown(suggestions, cursorPosition, editor, suggestionDropdown, insertSuggestion, highlighter) {
var _getCaretCoordinates = getCaretCoordinates(editor, cursorPosition),
top = _getCaretCoordinates.top,
left = _getCaretCoordinates.left;
suggestionDropdown.style.left = "".concat(left, "px");
suggestionDropdown.style.top = "".concat(top + 20, "px"); // Position slightly below the caret
suggestionDropdown.innerHTML = suggestions.map(function (s) {
return "<div class=\"suggestion-item\">".concat(s, "</div>");
}).join('');
suggestionDropdown.style.display = 'block';
// Add event listeners to each suggestion item
suggestionDropdown.querySelectorAll('.suggestion-item').forEach(function (item) {
item.addEventListener('click', function () {
insertSuggestion(this.innerText, editor, suggestionDropdown, highlighter);
});
});
// Add the ArrowDown listener
editor.addEventListener('keydown', function (e) {
return handleArrowDown(e, editor, suggestionDropdown, insertSuggestion, highlighter);
});
}
// Function to hide the suggestions dropdown
function hideSuggestionsDropdown(editor, suggestionDropdown) {
suggestionDropdown.style.display = 'none';
editor.removeEventListener('keydown', handleArrowDown);
}
// Function to insert the selected suggestion into the editor
function insertSuggestion(suggestion, editor, suggestionDropdown, highlighter) {
var cursorPosition = editor.selectionStart;
var currentValue = editor.value;
var lastWord = currentValue.substring(0, cursorPosition).split(/\s/).pop();
// Replace the last word with the selected suggestion
var newValue = currentValue.substring(0, cursorPosition - lastWord.length) + suggestion + currentValue.substring(cursorPosition);
editor.value = newValue;
hideSuggestionsDropdown(editor, suggestionDropdown);
// Set the cursor position after the inserted word
var newCursorPosition = cursorPosition - lastWord.length + suggestion.length;
editor.setSelectionRange(newCursorPosition, newCursorPosition);
// Update syntax highlighting
// const highlight = null;
updateSyntaxHighlighting(editor, highlighter);
}
// Function to get the caret (cursor) position in terms of pixel coordinates
function getCaretCoordinates(editor, position) {
var div = document.createElement('div');
var span = document.createElement('span');
var copyStyle = getComputedStyle(editor);
var _iterator = _createForOfIteratorHelper(copyStyle),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var prop = _step.value;
div.style[prop] = copyStyle[prop];
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
div.textContent = editor.value.substring(0, position);
span.textContent = editor.value.substring(position) || '.';
div.appendChild(span);
document.body.appendChild(div);
var top = span.offsetTop,
left = span.offsetLeft;
document.body.removeChild(div);
return {
top: top,
left: left
};
}
// Main function to handle suggestions
export function handleSuggestions(editor, suggestionDropdown, languageSelector, highlighter) {
// const lang = languageSelector.value;
var lang = 'javascript';
var cursorPosition = editor.selectionStart;
var currentValue = editor.value.substring(0, cursorPosition);
var lastWord = currentValue.split(/\s/).pop();
if (lastWord.trim()) {
// Combine reserved words and defined variables/objects for suggestions
var suggestions = [].concat(_toConsumableArray(languages[lang].reservedWords.filter(function (word) {
return word.startsWith(lastWord);
})), _toConsumableArray(Array.from(definedVariables).filter(function (varName) {
return varName.startsWith(lastWord);
})), _toConsumableArray(Array.from(definedObjects).filter(function (objName) {
return objName.startsWith(lastWord);
})));
if (suggestions.length > 0) {
showSuggestionsDropdown(suggestions, cursorPosition, editor, suggestionDropdown, insertSuggestion, highlighter);
} else {
hideSuggestionsDropdown(editor, suggestionDropdown);
}
}
}