UNPKG

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
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); } } }