You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2025/05/11 05:53:46 UTC
(camel) branch main updated: CAMEL-21945: camel-jbang edit plugin - refactor CamelNanoLspEditor class to inherit from Jline's Nano class (#17863)
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 12f7f3adc0b CAMEL-21945: camel-jbang edit plugin - refactor CamelNanoLspEditor class to inherit from Jline's Nano class (#17863)
12f7f3adc0b is described below
commit 12f7f3adc0ba7f847b2416d5c0671a93316da84f
Author: John Poth <po...@gmail.com>
AuthorDate: Sun May 11 07:53:41 2025 +0200
CAMEL-21945: camel-jbang edit plugin - refactor CamelNanoLspEditor class to inherit from Jline's Nano class (#17863)
---
.../core/commands/edit/CamelNanoLspEditor.java | 3787 +-------------------
parent/pom.xml | 2 +-
2 files changed, 106 insertions(+), 3683 deletions(-)
diff --git a/dsl/camel-jbang/camel-jbang-plugin-edit/src/main/java/org/apache/camel/dsl/jbang/core/commands/edit/CamelNanoLspEditor.java b/dsl/camel-jbang/camel-jbang-plugin-edit/src/main/java/org/apache/camel/dsl/jbang/core/commands/edit/CamelNanoLspEditor.java
index 1adb67109de..f0dd77139e2 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-edit/src/main/java/org/apache/camel/dsl/jbang/core/commands/edit/CamelNanoLspEditor.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-edit/src/main/java/org/apache/camel/dsl/jbang/core/commands/edit/CamelNanoLspEditor.java
@@ -16,43 +16,13 @@
*/
package org.apache.camel.dsl.jbang.core.commands.edit;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.PathMatcher;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.Iterator;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
import com.github.cameltooling.lsp.internal.CamelLanguageServer;
import com.github.cameltooling.lsp.internal.CamelTextDocumentService;
@@ -68,7 +38,6 @@ import org.apache.camel.tooling.util.Strings;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionList;
import org.eclipse.lsp4j.CompletionParams;
-import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.InsertReplaceEdit;
import org.eclipse.lsp4j.MarkupContent;
import org.eclipse.lsp4j.Position;
@@ -78,3117 +47,94 @@ import org.eclipse.lsp4j.TextDocumentItem;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.jline.builtins.ConfigurationPath;
+import org.jline.builtins.Nano;
import org.jline.builtins.Options;
-import org.jline.builtins.SyntaxHighlighter;
-import org.jline.keymap.BindingReader;
-import org.jline.keymap.KeyMap;
-import org.jline.reader.Editor;
-import org.jline.terminal.Attributes;
-import org.jline.terminal.Attributes.ControlChar;
-import org.jline.terminal.Attributes.InputFlag;
-import org.jline.terminal.Attributes.LocalFlag;
-import org.jline.terminal.MouseEvent;
-import org.jline.terminal.Size;
import org.jline.terminal.Terminal;
-import org.jline.terminal.Terminal.Signal;
-import org.jline.terminal.Terminal.SignalHandler;
import org.jline.utils.AttributedString;
-import org.jline.utils.AttributedStringBuilder;
import org.jline.utils.AttributedStyle;
-import org.jline.utils.Display;
-import org.jline.utils.InfoCmp.Capability;
-import org.jline.utils.Status;
-import org.mozilla.universalchardet.UniversalDetector;
-import static org.jline.builtins.SyntaxHighlighter.DEFAULT_NANORC_FILE;
-import static org.jline.keymap.KeyMap.KEYMAP_LENGTH;
-import static org.jline.keymap.KeyMap.alt;
-import static org.jline.keymap.KeyMap.ctrl;
-import static org.jline.keymap.KeyMap.del;
-import static org.jline.keymap.KeyMap.key;
-
-public class CamelNanoLspEditor implements Editor {
-
- // Final fields
- protected final Terminal terminal;
- protected final Display display;
- protected final BindingReader bindingReader;
- protected final Size size;
- protected final Path root;
- protected final int vsusp;
- private final List<Path> syntaxFiles = new ArrayList<>();
-
- // Keys
- protected KeyMap<Operation> keys;
-
- // Configuration
- public String title = "Camel JBang";
- public boolean printLineNumbers = false;
- public boolean wrapping = false;
- public boolean smoothScrolling = true;
- public boolean mouseSupport = true;
- public boolean oneMoreLine = true;
- public boolean constantCursor = false;
- public boolean quickBlank = false;
- public int tabs = 4;
- public String brackets = "\"’)>]}";
- public String matchBrackets = "(<[{)>]}";
- public String punct = "!.?";
- public String quoteStr = "^([ \\t]*[#:>\\|}])+";
- private boolean restricted = false;
- private String syntaxName;
- private boolean writeBackup = false;
- private boolean atBlanks = false;
- private boolean view = false;
- private boolean cut2end = false;
- private boolean tempFile = false;
- private String historyLog = null;
- private boolean tabsToSpaces = false;
- private boolean autoIndent = false;
-
- // Input
- protected final List<Buffer> buffers = new ArrayList<>();
- protected int bufferIndex;
- protected Buffer buffer;
-
- protected String message;
- protected String errorMessage = null;
- protected int nbBindings = 0;
-
- protected LinkedHashMap<String, String> shortcuts;
-
- protected String editMessage;
- protected final StringBuilder editBuffer = new StringBuilder();
-
- protected boolean searchCaseSensitive;
- protected boolean searchRegexp;
- protected boolean searchBackwards;
- protected String searchTerm;
- protected int matchedLength = -1;
- protected PatternHistory patternHistory = new PatternHistory(null);
- protected WriteMode writeMode = WriteMode.WRITE;
- protected List<String> cutbuffer = new ArrayList<>();
- protected boolean mark = false;
- protected boolean highlight = true;
- private boolean searchToReplace = false;
- protected boolean readNewBuffer = true;
- private boolean nanorcIgnoreErrors;
- private final boolean windowsTerminal;
- private boolean insertHelp = false;
- private boolean help = false;
- private Box suggestionBox;
- private List<AttributedString> suggestions;
- private List<List<AttributedString>> documentation;
- private final LocalCamelDocumentService camelDocumentService = new LocalCamelDocumentService();
- private int mouseX;
- private int mouseY;
-
- protected enum WriteMode {
- WRITE,
- APPEND,
- PREPEND
- }
-
- protected enum WriteFormat {
- UNIX,
- DOS,
- MAC
- }
-
- protected enum CursorMovement {
- RIGHT,
- LEFT,
- STILL
- }
-
- public static String[] usage() {
- return new String[] {
- "nano - edit files",
- "Usage: nano [OPTIONS] [FILES]",
- " -? --help Show help",
- " -B --backup When saving a file, back up the previous version of it, using the current filename",
- " suffixed with a tilde (~).",
- " -I --ignorercfiles Don't look at the system's nanorc nor at the user's nanorc.",
- " -Q --quotestr=regex Set the regular expression for matching the quoting part of a line.",
- " -T --tabsize=number Set the size (width) of a tab to number columns.",
- " -U --quickblank Do quick status-bar blanking: status-bar messages will disappear after 1 keystroke.",
- " -c --constantshow Constantly show the cursor position on the status bar.",
- " -e --emptyline Do not use the line below the title bar, leaving it entirely blank.",
- " -j --jumpyscrolling Scroll the buffer contents per half-screen instead of per line.",
- " -l --linenumbers Display line numbers to the left of the text area.",
- " -m --mouse Enable mouse support, if available for your system.",
- " -$ --softwrap Enable 'soft wrapping'. ",
- " -a --atblanks Wrap lines at whitespace instead of always at the edge of the screen.",
- " -R --restricted Restricted mode: don't allow suspending; don't allow a file to be appended to,",
- " prepended to, or saved under a different name if it already has one;",
- " and don't use backup files.",
- " -Y --syntax=name The name of the syntax highlighting to use.",
- " -z --suspend Enable the ability to suspend nano using the system's suspend keystroke (usually ^Z).",
- " -v --view Don't allow the contents of the file to be altered: read-only mode.",
- " -k --cutfromcursor Make the 'Cut Text' command cut from the current cursor position to the end of the line",
- " -t --tempfile Save a changed buffer without prompting (when exiting with ^X).",
- " -H --historylog=name Log search strings to file, so they can be retrieved in later sessions",
- " -E --tabstospaces Convert typed tabs to spaces.",
- " -i --autoindent Indent new lines to the previous line's indentation."
- };
- }
-
- protected class Buffer {
- String file;
- Charset charset;
- WriteFormat format = WriteFormat.UNIX;
- List<String> lines;
-
- int firstLineToDisplay;
- int firstColumnToDisplay = 0;
- int offsetInLineToDisplay;
-
- int line;
- List<LinkedList<Integer>> offsets = new ArrayList<>();
- int offsetInLine;
- int column;
- int wantedColumn;
- boolean uncut = false;
- int[] markPos = { -1, -1 }; // line, offsetInLine + column
- SyntaxHighlighter syntaxHighlighter;
-
- boolean dirty;
-
- protected Buffer(String file) {
- this.file = file;
- this.syntaxHighlighter = SyntaxHighlighter.build(root.resolve(file), syntaxName);
- }
-
- void open() throws IOException {
- if (lines != null) {
- return;
- }
-
- lines = new ArrayList<>();
- lines.add("");
- charset = Charset.defaultCharset();
- computeAllOffsets();
-
- if (file == null) {
- return;
- }
-
- Path path = root.resolve(file);
- if (Files.isDirectory(path)) {
- setMessage("\"" + file + "\" is a directory");
- return;
- }
-
- try (InputStream fis = Files.newInputStream(path)) {
- read(fis);
- } catch (IOException e) {
- setMessage("Error reading " + file + ": " + e.getMessage());
- }
- }
-
- void open(InputStream is) throws IOException {
-
- if (lines != null) {
- return;
- }
-
- lines = new ArrayList<>();
- lines.add("");
- charset = Charset.defaultCharset();
- computeAllOffsets();
-
- read(is);
- }
-
- void read(InputStream fis) throws IOException {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- byte[] buffer = new byte[4096];
- int remaining;
- while ((remaining = fis.read(buffer)) > 0) {
- bos.write(buffer, 0, remaining);
- }
- byte[] bytes = bos.toByteArray();
-
- try {
- UniversalDetector detector = new UniversalDetector(null);
- detector.handleData(bytes, 0, bytes.length);
- detector.dataEnd();
- if (detector.getDetectedCharset() != null) {
- charset = Charset.forName(detector.getDetectedCharset());
- }
- } catch (Throwable t) {
- // Ignore
- }
-
- // TODO: detect format, do not eat last newline
- try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes), charset))) {
- String line;
- lines.clear();
- while ((line = reader.readLine()) != null) {
- lines.add(line);
- }
- }
- if (lines.isEmpty()) {
- lines.add("");
- }
- computeAllOffsets();
- moveToChar(0);
- }
-
- private int charPosition(int displayPosition) {
- return charPosition(line, displayPosition, CursorMovement.STILL);
- }
-
- private int charPosition(int displayPosition, CursorMovement move) {
- return charPosition(line, displayPosition, move);
- }
-
- private int charPosition(int line, int displayPosition) {
- return charPosition(line, displayPosition, CursorMovement.STILL);
- }
-
- private int charPosition(int line, int displayPosition, CursorMovement move) {
- int out = lines.get(line).length();
- if (!lines.get(line).contains("\t") || displayPosition == 0) {
- out = displayPosition;
- } else if (displayPosition < length(lines.get(line))) {
- int rdiff = 0;
- int ldiff = 0;
- for (int i = 0; i < lines.get(line).length(); i++) {
- int dp = length(lines.get(line).substring(0, i));
- if (move == CursorMovement.LEFT) {
- if (dp <= displayPosition) {
- out = i;
- } else {
- break;
- }
- } else if (move == CursorMovement.RIGHT) {
- if (dp >= displayPosition) {
- out = i;
- break;
- }
- } else if (move == CursorMovement.STILL) {
- if (dp <= displayPosition) {
- ldiff = displayPosition - dp;
- out = i;
- } else if (dp >= displayPosition) {
- rdiff = dp - displayPosition;
- if (rdiff < ldiff) {
- out = i;
- }
- break;
- }
- }
- }
- }
- return out;
- }
-
- String blanks(int nb) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < nb; i++) {
- sb.append(' ');
- }
- return sb.toString();
- }
-
- void insert(String insert) {
- String text = lines.get(line);
- int pos = charPosition(offsetInLine + column);
- insert = insert.replaceAll("\r\n", "\n");
- insert = insert.replaceAll("\r", "\n");
- if (tabsToSpaces && insert.length() == 1 && insert.charAt(0) == '\t') {
- int len = pos == text.length() ? length(text + insert) : length(text.substring(0, pos) + insert);
- insert = blanks(len - offsetInLine - column);
- }
- if (autoIndent && insert.length() == 1 && insert.charAt(0) == '\n') {
- for (char c : lines.get(line).toCharArray()) {
- if (c == ' ') {
- insert += c;
- } else if (c == '\t') {
- insert += c;
- } else {
- break;
- }
- }
- }
- String mod;
- String tail = "";
- if (pos == text.length()) {
- mod = text + insert;
- } else {
- mod = text.substring(0, pos) + insert;
- tail = text.substring(pos);
- }
- List<String> ins = new ArrayList<>();
- int last = 0;
- int idx = mod.indexOf('\n', last);
- while (idx >= 0) {
- ins.add(mod.substring(last, idx));
- last = idx + 1;
- idx = mod.indexOf('\n', last);
- }
- ins.add(mod.substring(last) + tail);
- int curPos = length(mod.substring(last));
- lines.set(line, ins.get(0));
- offsets.set(line, computeOffsets(ins.get(0)));
- for (int i = 1; i < ins.size(); i++) {
- ++line;
- lines.add(line, ins.get(i));
- offsets.add(line, computeOffsets(ins.get(i)));
- }
- moveToChar(curPos);
- ensureCursorVisible();
- dirty = true;
- }
-
- void computeAllOffsets() {
- offsets.clear();
- for (String text : lines) {
- offsets.add(computeOffsets(text));
- }
- }
-
- LinkedList<Integer> computeOffsets(String line) {
- String text = new AttributedStringBuilder().tabs(tabs).append(line).toString();
- int width = size.getColumns() - (printLineNumbers ? 8 : 0);
- LinkedList<Integer> offsets = new LinkedList<>();
- offsets.add(0);
- if (wrapping) {
- int last = 0;
- int prevword = 0;
- boolean inspace = false;
- for (int i = 0; i < text.length(); i++) {
- if (isBreakable(text.charAt(i))) {
- inspace = true;
- } else if (inspace) {
- prevword = i;
- inspace = false;
- }
- if (i == last + width - 1) {
- if (prevword == last) {
- prevword = i;
- }
- offsets.add(prevword);
- last = prevword;
- }
- }
- }
- return offsets;
- }
-
- boolean isBreakable(char ch) {
- return !atBlanks || ch == ' ';
- }
-
- void moveToChar(int pos) {
- moveToChar(pos, CursorMovement.STILL);
- }
-
- void moveToChar(int pos, CursorMovement move) {
- if (!wrapping) {
- if (pos > column && pos - firstColumnToDisplay + 1 > width()) {
- firstColumnToDisplay = offsetInLine + column - 6;
- } else if (pos < column && firstColumnToDisplay + 5 > pos) {
- firstColumnToDisplay = Math.max(0, firstColumnToDisplay - width() + 5);
- }
- }
- if (lines.get(line).contains("\t")) {
- int cpos = charPosition(pos, move);
- if (cpos < lines.get(line).length()) {
- pos = length(lines.get(line).substring(0, cpos));
- } else {
- pos = length(lines.get(line));
- }
- }
- offsetInLine = prevLineOffset(line, pos + 1).get();
- column = pos - offsetInLine;
- }
-
- void delete(int count) {
- while (--count >= 0 && moveRight(1) && backspace(1))
- ;
- }
-
- boolean backspace(int count) {
- while (count > 0) {
- String text = lines.get(line);
- int pos = charPosition(offsetInLine + column);
- if (pos == 0) {
- if (line == 0) {
- bof();
- return false;
- }
- String prev = lines.get(--line);
- lines.set(line, prev + text);
- offsets.set(line, computeOffsets(prev + text));
- moveToChar(length(prev));
- lines.remove(line + 1);
- offsets.remove(line + 1);
- count--;
- } else {
- int nb = Math.min(pos, count);
- int curPos = length(text.substring(0, pos - nb));
- text = text.substring(0, pos - nb) + text.substring(pos);
- lines.set(line, text);
- offsets.set(line, computeOffsets(text));
- moveToChar(curPos);
- count -= nb;
- }
- dirty = true;
- }
- ensureCursorVisible();
- return true;
- }
-
- boolean moveLeft(int chars) {
- boolean ret = true;
- while (--chars >= 0) {
- if (offsetInLine + column > 0) {
- moveToChar(offsetInLine + column - 1, CursorMovement.LEFT);
- } else if (line > 0) {
- line--;
- moveToChar(length(getLine(line)));
- } else {
- bof();
- ret = false;
- break;
- }
- }
- wantedColumn = column;
- ensureCursorVisible();
- return ret;
- }
-
- boolean moveRight(int chars) {
- return moveRight(chars, false);
- }
-
- int width() {
- return size.getColumns()
- - (printLineNumbers ? 8 : 0)
- - (wrapping ? 0 : 1)
- - (firstColumnToDisplay > 0 ? 1 : 0);
- }
-
- boolean moveRight(int chars, boolean fromBeginning) {
- if (fromBeginning) {
- firstColumnToDisplay = 0;
- offsetInLine = 0;
- column = 0;
- chars = Math.min(chars, length(getLine(line)));
- }
- boolean ret = true;
- while (--chars >= 0) {
- int len = length(getLine(line));
- if (offsetInLine + column + 1 <= len) {
- moveToChar(offsetInLine + column + 1, CursorMovement.RIGHT);
- } else if (getLine(line + 1) != null) {
- line++;
- firstColumnToDisplay = 0;
- offsetInLine = 0;
- column = 0;
- } else {
- eof();
- ret = false;
- break;
- }
- }
- wantedColumn = column;
- ensureCursorVisible();
- return ret;
- }
-
- void moveDown(int lines) {
- cursorDown(lines);
- ensureCursorVisible();
- }
-
- void moveUp(int lines) {
- cursorUp(lines);
- ensureCursorVisible();
- }
-
- private Optional<Integer> prevLineOffset(int line, int offsetInLine) {
- if (line >= offsets.size()) {
- return Optional.empty();
- }
- Iterator<Integer> it = offsets.get(line).descendingIterator();
- while (it.hasNext()) {
- int off = it.next();
- if (off < offsetInLine) {
- return Optional.of(off);
- }
- }
- return Optional.empty();
- }
-
- private Optional<Integer> nextLineOffset(int line, int offsetInLine) {
- if (line >= offsets.size()) {
- return Optional.empty();
- }
- return offsets.get(line).stream().filter(o -> o > offsetInLine).findFirst();
- }
-
- void moveDisplayDown(int lines) {
- int height = size.getRows() - computeHeader().size() - computeFooter().size();
- // Adjust cursor
- while (--lines >= 0) {
- int lastLineToDisplay = firstLineToDisplay;
- if (!wrapping) {
- lastLineToDisplay += height - 1;
- } else {
- int off = offsetInLineToDisplay;
- for (int l = 0; l < height - 1; l++) {
- Optional<Integer> next = nextLineOffset(lastLineToDisplay, off);
- if (next.isPresent()) {
- off = next.get();
- } else {
- off = 0;
- lastLineToDisplay++;
- }
- }
- }
- if (getLine(lastLineToDisplay) == null) {
- eof();
- return;
- }
- Optional<Integer> next = nextLineOffset(firstLineToDisplay, offsetInLineToDisplay);
- if (next.isPresent()) {
- offsetInLineToDisplay = next.get();
- } else {
- offsetInLineToDisplay = 0;
- firstLineToDisplay++;
- }
- }
- }
-
- void moveDisplayUp(int lines) {
- int width = size.getColumns() - (printLineNumbers ? 8 : 0);
- while (--lines >= 0) {
- if (offsetInLineToDisplay > 0) {
- offsetInLineToDisplay = Math.max(0, offsetInLineToDisplay - (width - 1));
- } else if (firstLineToDisplay > 0) {
- firstLineToDisplay--;
- offsetInLineToDisplay = prevLineOffset(firstLineToDisplay, Integer.MAX_VALUE)
- .get();
- } else {
- bof();
- return;
- }
- }
- }
-
- private void cursorDown(int lines) {
- // Adjust cursor
- firstColumnToDisplay = 0;
- while (--lines >= 0) {
- if (!wrapping) {
- if (getLine(line + 1) != null) {
- line++;
- offsetInLine = 0;
- column = Math.min(length(getLine(line)), wantedColumn);
- } else {
- bof();
- break;
- }
- } else {
- String txt = getLine(line);
- Optional<Integer> off = nextLineOffset(line, offsetInLine);
- if (off.isPresent()) {
- offsetInLine = off.get();
- } else if (getLine(line + 1) == null) {
- eof();
- break;
- } else {
- line++;
- offsetInLine = 0;
- txt = getLine(line);
- }
- int next = nextLineOffset(line, offsetInLine).orElse(length(txt));
- column = Math.min(wantedColumn, next - offsetInLine);
- }
- }
- moveToChar(offsetInLine + column);
- }
-
- private void cursorUp(int lines) {
- firstColumnToDisplay = 0;
- while (--lines >= 0) {
- if (!wrapping) {
- if (line > 0) {
- line--;
- column = Math.min(length(getLine(line)) - offsetInLine, wantedColumn);
- } else {
- bof();
- break;
- }
- } else {
- Optional<Integer> prev = prevLineOffset(line, offsetInLine);
- if (prev.isPresent()) {
- offsetInLine = prev.get();
- } else if (line > 0) {
- line--;
- offsetInLine = prevLineOffset(line, Integer.MAX_VALUE).get();
- int next = nextLineOffset(line, offsetInLine).orElse(length(getLine(line)));
- column = Math.min(wantedColumn, next - offsetInLine);
- } else {
- bof();
- break;
- }
- }
- }
- moveToChar(offsetInLine + column);
- }
-
- void ensureCursorVisible() {
- List<AttributedString> header = computeHeader();
- int rwidth = size.getColumns();
- int height = size.getRows() - header.size() - computeFooter().size();
-
- while (line < firstLineToDisplay || line == firstLineToDisplay && offsetInLine < offsetInLineToDisplay) {
- moveDisplayUp(smoothScrolling ? 1 : height / 2);
- }
-
- while (true) {
- int cursor = computeCursorPosition(header.size() * size.getColumns() + (printLineNumbers ? 8 : 0), rwidth);
- if (cursor >= (height + header.size()) * rwidth) {
- moveDisplayDown(smoothScrolling ? 1 : height / 2);
- } else {
- break;
- }
- }
- }
-
- void eof() {
- }
-
- void bof() {
- }
-
- void resetDisplay() {
- column = offsetInLine + column;
- moveRight(column, true);
- }
-
- String getLine(int line) {
- return line < lines.size() ? lines.get(line) : null;
- }
-
- String getTitle() {
- return file != null ? "File: " + file : "New Buffer";
- }
-
- List<AttributedString> computeHeader() {
- String left = CamelNanoLspEditor.this.getTitle();
- String middle = null;
- String right = dirty ? "Modified" : " ";
-
- int width = size.getColumns();
- int mstart = 2 + left.length() + 1;
- int mend = width - 2 - 8;
-
- if (file == null) {
- middle = "New Buffer";
- } else {
- int max = mend - mstart;
- String src = file;
- if ("File: ".length() + src.length() > max) {
- int lastSep = src.lastIndexOf('/');
- if (lastSep > 0) {
- String p1 = src.substring(lastSep);
- String p0 = src.substring(0, lastSep);
- while (p0.startsWith(".")) {
- p0 = p0.substring(1);
- }
- int nb = max - p1.length() - "File: ...".length();
- int cut;
- cut = Math.max(0, Math.min(p0.length(), p0.length() - nb));
- middle = "File: ..." + p0.substring(cut) + p1;
- }
- if (middle == null || middle.length() > max) {
- left = null;
- max = mend - 2;
- int nb = max - "File: ...".length();
- int cut = Math.max(0, Math.min(src.length(), src.length() - nb));
- middle = "File: ..." + src.substring(cut);
- if (middle.length() > max) {
- middle = middle.substring(0, max);
- }
- }
- } else {
- middle = "File: " + src;
- }
- }
-
- int pos = 0;
- AttributedStringBuilder sb = new AttributedStringBuilder();
- sb.style(AttributedStyle.INVERSE);
- sb.append(" ");
- pos += 2;
-
- if (left != null) {
- sb.append(left);
- pos += left.length();
- sb.append(" ");
- pos += 1;
- for (int i = 1; i < (size.getColumns() - middle.length()) / 2 - left.length() - 1 - 2; i++) {
- sb.append(" ");
- pos++;
- }
- }
- sb.append(middle);
- pos += middle.length();
- while (pos < width - 8 - 2) {
- sb.append(" ");
- pos++;
- }
- sb.append(right);
- sb.append(" \n");
- if (oneMoreLine) {
- return Collections.singletonList(sb.toAttributedString());
- } else {
- return Arrays.asList(sb.toAttributedString(), new AttributedString("\n"));
- }
- }
-
- void highlightDisplayedLine(int curLine, int curOffset, int nextOffset, AttributedStringBuilder line) {
- AttributedString disp = highlight
- ? syntaxHighlighter.highlight(
- new AttributedStringBuilder().tabs(tabs).append(getLine(curLine)))
- : new AttributedStringBuilder()
- .tabs(tabs)
- .append(getLine(curLine))
- .toAttributedString();
- int[] hls = highlightStart();
- int[] hle = highlightEnd();
- if (hls[0] == -1 || hle[0] == -1) {
- line.append(disp.columnSubSequence(curOffset, nextOffset));
- } else if (hls[0] == hle[0]) {
- if (curLine == hls[0]) {
- if (hls[1] > nextOffset) {
- line.append(disp.columnSubSequence(curOffset, nextOffset));
- } else if (hls[1] < curOffset) {
- if (hle[1] > nextOffset) {
- line.append(disp.columnSubSequence(curOffset, nextOffset), AttributedStyle.INVERSE);
- } else if (hle[1] > curOffset) {
- line.append(disp.columnSubSequence(curOffset, hle[1]), AttributedStyle.INVERSE);
- line.append(disp.columnSubSequence(hle[1], nextOffset));
- } else {
- line.append(disp.columnSubSequence(curOffset, nextOffset));
- }
- } else {
- line.append(disp.columnSubSequence(curOffset, hls[1]));
- if (hle[1] > nextOffset) {
- line.append(disp.columnSubSequence(hls[1], nextOffset), AttributedStyle.INVERSE);
- } else {
- line.append(disp.columnSubSequence(hls[1], hle[1]), AttributedStyle.INVERSE);
- line.append(disp.columnSubSequence(hle[1], nextOffset));
- }
- }
- } else {
- line.append(disp.columnSubSequence(curOffset, nextOffset));
- }
- } else {
- if (curLine > hls[0] && curLine < hle[0]) {
- line.append(disp.columnSubSequence(curOffset, nextOffset), AttributedStyle.INVERSE);
- } else if (curLine == hls[0]) {
- if (hls[1] > nextOffset) {
- line.append(disp.columnSubSequence(curOffset, nextOffset));
- } else if (hls[1] < curOffset) {
- line.append(disp.columnSubSequence(curOffset, nextOffset), AttributedStyle.INVERSE);
- } else {
- line.append(disp.columnSubSequence(curOffset, hls[1]));
- line.append(disp.columnSubSequence(hls[1], nextOffset), AttributedStyle.INVERSE);
- }
- } else if (curLine == hle[0]) {
- if (hle[1] < curOffset) {
- line.append(disp.columnSubSequence(curOffset, nextOffset));
- } else if (hle[1] > nextOffset) {
- line.append(disp.columnSubSequence(curOffset, nextOffset), AttributedStyle.INVERSE);
- } else {
- line.append(disp.columnSubSequence(curOffset, hle[1]), AttributedStyle.INVERSE);
- line.append(disp.columnSubSequence(hle[1], nextOffset));
- }
- } else {
- line.append(disp.columnSubSequence(curOffset, nextOffset));
- }
- }
- }
-
- List<AttributedString> getDisplayedLines(int nbLines, List<Diagnostic> diagnostics) {
- AttributedStyle s = AttributedStyle.DEFAULT.foreground(AttributedStyle.BLACK + AttributedStyle.BRIGHT);
- AttributedString cut = new AttributedString("…", s);
- AttributedString ret = new AttributedString("↩", s);
-
- List<AttributedString> newLines = new ArrayList<>();
- int rwidth = size.getColumns();
- int width = rwidth - (printLineNumbers ? 8 : 0);
- int curLine = firstLineToDisplay;
- int curOffset = offsetInLineToDisplay;
- int prevLine = -1;
- if (highlight) {
- syntaxHighlighter.reset();
- for (int i = Math.max(0, curLine - nbLines); i < curLine; i++) {
- syntaxHighlighter.highlight(getLine(i));
- }
- }
- for (int terminalLine = 0; terminalLine < nbLines; terminalLine++) {
- AttributedStringBuilder line = new AttributedStringBuilder().tabs(tabs);
- if (printLineNumbers && curLine < lines.size()) {
- line.style(s);
- if (curLine != prevLine) {
- line.append(String.format("%7d ", curLine + 1));
- } else {
- line.append(" ‧ ");
- }
- line.style(AttributedStyle.DEFAULT);
- prevLine = curLine;
- }
- if (curLine >= lines.size()) {
- // Nothing to do
- } else if (!wrapping) {
- AttributedString disp = new AttributedStringBuilder()
- .tabs(tabs)
- .append(getLine(curLine))
- .toAttributedString();
- if (this.line == curLine) {
- int cutCount = 1;
- if (firstColumnToDisplay > 0) {
- line.append(cut);
- cutCount = 2;
- }
- if (disp.columnLength() - firstColumnToDisplay >= width - (cutCount - 1) * cut.columnLength()) {
- highlightDisplayedLine(
- curLine,
- firstColumnToDisplay,
- firstColumnToDisplay + width - cutCount * cut.columnLength(),
- line);
- line.append(cut);
- } else {
- highlightDisplayedLine(curLine, firstColumnToDisplay, disp.columnLength(), line);
- }
- } else {
- if (disp.columnLength() >= width) {
- highlightDisplayedLine(curLine, 0, width - cut.columnLength(), line);
- line.append(cut);
- } else {
- highlightDisplayedLine(curLine, 0, disp.columnLength(), line);
- }
- }
- curLine++;
- } else {
- Optional<Integer> nextOffset = nextLineOffset(curLine, curOffset);
- if (nextOffset.isPresent()) {
- highlightDisplayedLine(curLine, curOffset, nextOffset.get(), line);
- line.append(ret);
- curOffset = nextOffset.get();
- } else {
- highlightDisplayedLine(curLine, curOffset, Integer.MAX_VALUE, line);
- curLine++;
- curOffset = 0;
- }
- }
- line.append('\n');
- newLines.add(line.toAttributedString());
- }
- // add tool tips if any
- if (diagnostics != null) {
- for (Diagnostic diagnostic : diagnostics) {
- Range range = diagnostic.getRange();
- Position start = range.getStart();
- Position end = range.getEnd();
- //TODO when they aren't on the same line
- if (start.getLine() == end.getLine()) {
- int line = end.getLine() - firstLineToDisplay;
- AttributedString attributedString = newLines.get(line);
- AttributedStringBuilder builder = new AttributedStringBuilder(attributedString.length());
- builder.append(attributedString.subSequence(0, start.getCharacter()));
- builder.append(attributedString.subSequence(start.getCharacter(), end.getCharacter()),
- AttributedStyle.DEFAULT.underline().foreground(AttributedStyle.RED));
- builder.append(attributedString.subSequence(end.getCharacter(), attributedString.length()));
- newLines.set(line, builder.toAttributedString());
- if (line == mouseY - 1 && mouseX >= start.getCharacter() && mouseX <= end.getCharacter()) {
- String message = diagnostic.getMessage();
- if (Strings.isEmpty(message)) {
- continue;
- }
- try {
- // sometimes the message is URL encoded
- message = java.net.URLDecoder.decode(message, StandardCharsets.UTF_8);
- } catch (Exception e) {
- //ignore
- }
- // remove trailing carriage returns
- message = message.replaceAll("\\s+$", "");
- // build tool tip box
- int xi = start.getCharacter();
- int dBoxSize = message.length() + 2;
- int maxWidth = (int) Math.round((size.getColumns() - xi) * 0.60); // let's do 60% of what's left of the screen
- int xl = Math.min(dBoxSize + xi, xi + maxWidth);
- //adjust content
- List<AttributedString> boxLines = adjustLines(
- Collections.singletonList(new AttributedString(message)), dBoxSize - 2, xl - xi - 2);
- if (!Strings.isEmpty(message)) {
- // TODO: display above current pos if there is no space at the bottom
- Box box = new Box(xi, start.getLine() + 1, xl, start.getLine() + boxLines.size() + 2);
- box.setLines(boxLines);
- addBoxBorders(newLines, box);
- addBoxLines(box, newLines);
- }
- }
- }
- }
- }
- return newLines;
- }
-
- public void moveTo(int x, int y) {
- if (printLineNumbers) {
- x = Math.max(x - 8, 0);
- }
- line = firstLineToDisplay;
- offsetInLine = offsetInLineToDisplay;
- wantedColumn = x;
- cursorDown(y);
- }
-
- public void gotoLine(int x, int y) {
- line = y < lines.size() ? y : lines.size() - 1;
- x = Math.min(x, length(lines.get(line)));
- firstLineToDisplay = line > 0 ? line - 1 : line;
- offsetInLine = 0;
- offsetInLineToDisplay = 0;
- column = 0;
- moveRight(x);
- }
-
- public int getDisplayedCursor() {
- return computeCursorPosition(printLineNumbers ? 8 : 0, size.getColumns() + 1);
- }
-
- private int computeCursorPosition(int cursor, int rwidth) {
- int cur = firstLineToDisplay;
- int off = offsetInLineToDisplay;
- while (true) {
- if (cur < line || off < offsetInLine) {
- if (!wrapping) {
- cursor += rwidth;
- cur++;
- } else {
- cursor += rwidth;
- Optional<Integer> next = nextLineOffset(cur, off);
- if (next.isPresent()) {
- off = next.get();
- } else {
- cur++;
- off = 0;
- }
- }
- } else if (cur == line) {
- if (!wrapping && column > firstColumnToDisplay + width()) {
- while (column > firstColumnToDisplay + width()) {
- firstColumnToDisplay += width();
- }
- }
- cursor += column - firstColumnToDisplay + (firstColumnToDisplay > 0 ? 1 : 0);
- break;
- } else {
- throw new IllegalStateException();
- }
- }
- return cursor;
- }
-
- char getCurrentChar() {
- String str = lines.get(line);
- if (column + offsetInLine < str.length()) {
- return str.charAt(column + offsetInLine);
- } else if (line < lines.size() - 1) {
- return '\n';
- } else {
- return 0;
- }
- }
-
- public void beginningOfLine() {
- column = offsetInLine = 0;
- wantedColumn = 0;
- ensureCursorVisible();
- }
-
- public void endOfLine() {
- int x = length(lines.get(line));
- moveRight(x, true);
- }
-
- public void prevPage() {
- int height = size.getRows() - computeHeader().size() - computeFooter().size();
- scrollUp(height - 2);
- column = 0;
- firstLineToDisplay = line;
- offsetInLineToDisplay = offsetInLine;
- }
-
- public void nextPage() {
- int height = size.getRows() - computeHeader().size() - computeFooter().size();
- scrollDown(height - 2);
- column = 0;
- firstLineToDisplay = line;
- offsetInLineToDisplay = offsetInLine;
- }
-
- public void scrollUp(int lines) {
- cursorUp(lines);
- moveDisplayUp(lines);
- }
-
- public void scrollDown(int lines) {
- cursorDown(lines);
- moveDisplayDown(lines);
- }
-
- public void firstLine() {
- line = 0;
- offsetInLine = column = 0;
- ensureCursorVisible();
- }
-
- public void lastLine() {
- line = lines.size() - 1;
- offsetInLine = column = 0;
- ensureCursorVisible();
- }
-
- boolean nextSearch() {
- boolean out = false;
- if (searchTerm == null) {
- setMessage("No current search pattern");
- return false;
- }
- setMessage(null);
- int cur = line;
- int dir = searchBackwards ? -1 : +1;
- int newPos = -1;
- int newLine = -1;
- // Search on current line
- List<Integer> curRes = doSearch(lines.get(line));
- if (searchBackwards) {
- Collections.reverse(curRes);
- }
- for (int r : curRes) {
- if (searchBackwards ? r < offsetInLine + column : r > offsetInLine + column) {
- newPos = r;
- newLine = line;
- break;
- }
- }
- // Check other lines
- if (newPos < 0) {
- while (true) {
- cur = (cur + dir + lines.size()) % lines.size();
- if (cur == line) {
- break;
- }
- List<Integer> res = doSearch(lines.get(cur));
- if (!res.isEmpty()) {
- newPos = searchBackwards ? res.get(res.size() - 1) : res.get(0);
- newLine = cur;
- break;
- }
- }
- }
- if (newPos < 0) {
- if (!curRes.isEmpty()) {
- newPos = curRes.get(0);
- newLine = line;
- }
- }
- if (newPos >= 0) {
- if (newLine == line && newPos == offsetInLine + column) {
- setMessage("This is the only occurence");
- return false;
- }
- if ((searchBackwards && (newLine > line || (newLine == line && newPos > offsetInLine + column)))
- || (!searchBackwards
- && (newLine < line || (newLine == line && newPos < offsetInLine + column)))) {
- setMessage("Search Wrapped");
- }
- line = newLine;
- moveRight(newPos, true);
- out = true;
- } else {
- setMessage("\"" + searchTerm + "\" not found");
- }
- return out;
- }
-
- private List<Integer> doSearch(String text) {
- Pattern pat = Pattern.compile(
- searchTerm,
- (searchCaseSensitive ? 0 : Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)
- | (searchRegexp ? 0 : Pattern.LITERAL));
- Matcher m = pat.matcher(text);
- List<Integer> res = new ArrayList<>();
- while (m.find()) {
- res.add(m.start());
- matchedLength = m.group(0).length();
- }
- return res;
- }
-
- protected int[] highlightStart() {
- int[] out = { -1, -1 };
- if (mark) {
- out = getMarkStart();
- } else if (searchToReplace) {
- out[0] = line;
- out[1] = offsetInLine + column;
- }
- return out;
- }
-
- protected int[] highlightEnd() {
- int[] out = { -1, -1 };
- if (mark) {
- out = getMarkEnd();
- } else if (searchToReplace && matchedLength > 0) {
- out[0] = line;
- int col = charPosition(offsetInLine + column) + matchedLength;
- if (col < lines.get(line).length()) {
- out[1] = length(lines.get(line).substring(0, col));
- } else {
- out[1] = length(lines.get(line));
- }
- }
- return out;
- }
-
- public void matching() {
- int opening = getCurrentChar();
- int idx = matchBrackets.indexOf(opening);
- if (idx >= 0) {
- int dir = (idx >= matchBrackets.length() / 2) ? -1 : +1;
- int closing = matchBrackets.charAt((idx + matchBrackets.length() / 2) % matchBrackets.length());
-
- int lvl = 1;
- int cur = line;
- int pos = offsetInLine + column;
- while (true) {
- if ((pos + dir >= 0) && (pos + dir < getLine(cur).length())) {
- pos += dir;
- } else if ((cur + dir >= 0) && (cur + dir < lines.size())) {
- cur += dir;
- pos = dir > 0 ? 0 : lines.get(cur).length() - 1;
- // Skip empty lines
- if (pos < 0 || pos >= lines.get(cur).length()) {
- continue;
- }
- } else {
- setMessage("No matching bracket");
- return;
- }
- int c = lines.get(cur).charAt(pos);
- if (c == opening) {
- lvl++;
- } else if (c == closing) {
- if (--lvl == 0) {
- line = cur;
- moveToChar(pos);
- ensureCursorVisible();
- return;
- }
- }
- }
- } else {
- setMessage("Not a bracket");
- }
- }
-
- private int length(String line) {
- return new AttributedStringBuilder().tabs(tabs).append(line).columnLength();
- }
-
- void copy() {
- if (uncut || cut2end || mark) {
- cutbuffer = new ArrayList<>();
- }
- if (mark) {
- int[] s = getMarkStart();
- int[] e = getMarkEnd();
- if (s[0] == e[0]) {
- cutbuffer.add(lines.get(s[0]).substring(charPosition(s[0], s[1]), charPosition(e[0], e[1])));
- } else {
- if (s[1] != 0) {
- cutbuffer.add(lines.get(s[0]).substring(charPosition(s[0], s[1])));
- s[0] = s[0] + 1;
- }
- for (int i = s[0]; i < e[0]; i++) {
- cutbuffer.add(lines.get(i));
- }
- if (e[1] != 0) {
- cutbuffer.add(lines.get(e[0]).substring(0, charPosition(e[0], e[1])));
- }
- }
- mark = false;
- mark();
- } else if (cut2end) {
- String l = lines.get(line);
- int col = charPosition(offsetInLine + column);
- cutbuffer.add(l.substring(col));
- moveRight(l.substring(col).length());
- } else {
- cutbuffer.add(lines.get(line));
- cursorDown(1);
- }
- uncut = false;
- }
-
- void cut() {
- cut(false);
- }
-
- void cut(boolean toEnd) {
- if (lines.size() > 1) {
- if (uncut || cut2end || toEnd || mark) {
- cutbuffer = new ArrayList<>();
- }
- if (mark) {
- int[] s = getMarkStart();
- int[] e = getMarkEnd();
- if (s[0] == e[0]) {
- String l = lines.get(s[0]);
- int cols = charPosition(s[0], s[1]);
- int cole = charPosition(e[0], e[1]);
- cutbuffer.add(l.substring(cols, cole));
- lines.set(s[0], l.substring(0, cols) + l.substring(cole));
- computeAllOffsets();
- moveRight(cols, true);
- } else {
- int ls = s[0];
- int cs = charPosition(s[0], s[1]);
- if (s[1] != 0) {
- String l = lines.get(s[0]);
- cutbuffer.add(l.substring(cs));
- lines.set(s[0], l.substring(0, cs));
- s[0] = s[0] + 1;
- }
- for (int i = s[0]; i < e[0]; i++) {
- cutbuffer.add(lines.get(s[0]));
- lines.remove(s[0]);
- }
- if (e[1] != 0) {
- String l = lines.get(s[0]);
- int col = charPosition(e[0], e[1]);
- cutbuffer.add(l.substring(0, col));
- lines.set(s[0], l.substring(col));
- }
- computeAllOffsets();
- gotoLine(cs, ls);
- }
- mark = false;
- mark();
- } else if (cut2end || toEnd) {
- String l = lines.get(line);
- int col = charPosition(offsetInLine + column);
- cutbuffer.add(l.substring(col));
- lines.set(line, l.substring(0, col));
- if (toEnd) {
- line++;
- while (true) {
- cutbuffer.add(lines.get(line));
- lines.remove(line);
- if (line > lines.size() - 1) {
- line--;
- break;
- }
- }
- }
- } else {
- cutbuffer.add(lines.get(line));
- lines.remove(line);
- offsetInLine = 0;
- if (line > lines.size() - 1) {
- line--;
- }
- }
- display.clear();
- computeAllOffsets();
- dirty = true;
- uncut = false;
- }
- }
-
- void uncut() {
- if (cutbuffer.isEmpty()) {
- return;
- }
- String l = lines.get(line);
- int col = charPosition(offsetInLine + column);
- if (cut2end) {
- lines.set(line, l.substring(0, col) + cutbuffer.get(0) + l.substring(col));
- computeAllOffsets();
- moveRight(col + cutbuffer.get(0).length(), true);
- } else if (col == 0) {
- lines.addAll(line, cutbuffer);
- computeAllOffsets();
- if (cutbuffer.size() > 1) {
- gotoLine(cutbuffer.get(cutbuffer.size() - 1).length(), line + cutbuffer.size());
- } else {
- moveRight(cutbuffer.get(0).length(), true);
- }
- } else {
- int gotol = line;
- if (cutbuffer.size() == 1) {
- lines.set(line, l.substring(0, col) + cutbuffer.get(0) + l.substring(col));
- } else {
- lines.set(line++, l.substring(0, col) + cutbuffer.get(0));
- gotol = line;
- lines.add(line, cutbuffer.get(cutbuffer.size() - 1) + l.substring(col));
- for (int i = cutbuffer.size() - 2; i > 0; i--) {
- gotol++;
- lines.add(line, cutbuffer.get(i));
- }
- }
- computeAllOffsets();
- if (cutbuffer.size() > 1) {
- gotoLine(cutbuffer.get(cutbuffer.size() - 1).length(), gotol);
- } else {
- moveRight(col + cutbuffer.get(0).length(), true);
- }
- }
- display.clear();
- dirty = true;
- uncut = true;
- }
-
- void mark() {
- if (mark) {
- markPos[0] = line;
- markPos[1] = offsetInLine + column;
- } else {
- markPos[0] = -1;
- markPos[1] = -1;
- }
- }
-
- int[] getMarkStart() {
- int[] out = { -1, -1 };
- if (!mark) {
- return out;
- }
- if (markPos[0] > line || (markPos[0] == line && markPos[1] > offsetInLine + column)) {
- out[0] = line;
- out[1] = offsetInLine + column;
- } else {
- out = markPos;
- }
- return out;
- }
-
- int[] getMarkEnd() {
- int[] out = { -1, -1 };
- if (!mark) {
- return out;
- }
- if (markPos[0] > line || (markPos[0] == line && markPos[1] > offsetInLine + column)) {
- out = markPos;
- } else {
- out[0] = line;
- out[1] = offsetInLine + column;
- }
- return out;
- }
-
- void replaceFromCursor(int chars, String string) {
- int pos = charPosition(offsetInLine + column);
- String text = lines.get(line);
- String mod = text.substring(0, pos) + string;
- if (chars + pos < text.length()) {
- mod += text.substring(chars + pos);
- }
- lines.set(line, mod);
- dirty = true;
- }
- }
-
- protected static class PatternHistory {
- private final Path historyFile;
- private final int size = 100;
- private List<String> patterns = new ArrayList<>();
- private int patternId = -1;
- private boolean lastMoveUp = false;
-
- public PatternHistory(Path historyFile) {
- this.historyFile = historyFile;
- load();
- }
-
- public String up(String hint) {
- String out = hint;
- if (patterns.size() > 0 && patternId < patterns.size()) {
- if (!lastMoveUp && patternId > 0 && patternId < patterns.size() - 1) {
- patternId++;
- }
- if (patternId < 0) {
- patternId = 0;
- }
- boolean found = false;
- for (int pid = patternId; pid < patterns.size(); pid++) {
- if (hint.isEmpty() || patterns.get(pid).startsWith(hint)) {
- patternId = pid + 1;
- out = patterns.get(pid);
- found = true;
- break;
- }
- }
- if (!found) {
- patternId = patterns.size();
- }
- }
- lastMoveUp = true;
- return out;
- }
-
- public String down(String hint) {
- String out = hint;
- if (!patterns.isEmpty()) {
- if (lastMoveUp) {
- patternId--;
- }
- if (patternId < 0) {
- patternId = -1;
- } else {
- boolean found = false;
- for (int pid = patternId; pid >= 0; pid--) {
- if (hint.length() == 0 || patterns.get(pid).startsWith(hint)) {
- patternId = pid - 1;
- out = patterns.get(pid);
- found = true;
- break;
- }
- }
- if (!found) {
- patternId = -1;
- }
- }
- }
- lastMoveUp = false;
- return out;
- }
-
- public void add(String pattern) {
- if (pattern.trim().isEmpty()) {
- return;
- }
- patterns.remove(pattern);
- if (patterns.size() > size) {
- patterns.remove(patterns.size() - 1);
- }
- patterns.add(0, pattern);
- patternId = -1;
- }
-
- public void persist() {
- if (historyFile == null) {
- return;
- }
- try {
- try (BufferedWriter writer = Files.newBufferedWriter(
- historyFile.toAbsolutePath(), StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
- for (String s : patterns) {
- if (!s.trim().isEmpty()) {
- writer.append(s);
- writer.newLine();
- }
- }
- }
- } catch (Exception e) {
- // ignore
- }
- }
-
- private void load() {
- if (historyFile == null) {
- return;
- }
- try {
- if (Files.exists(historyFile)) {
- patterns = new ArrayList<>();
- try (BufferedReader reader = Files.newBufferedReader(historyFile)) {
- reader.lines().forEach(line -> patterns.add(line));
- }
- }
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- public CamelNanoLspEditor(Terminal terminal, File root) {
- this(terminal, root.toPath());
- }
-
- public CamelNanoLspEditor(Terminal terminal, Path root) {
- this(terminal, root, null);
- }
-
- public CamelNanoLspEditor(Terminal terminal, Path root, Options opts) {
- this(terminal, root, opts, null);
- }
-
- @SuppressWarnings("this-escape")
- public CamelNanoLspEditor(Terminal terminal, Path root, Options opts, ConfigurationPath configPath) {
- this.camelDocumentService.init();
- this.terminal = terminal;
- this.windowsTerminal = terminal.getClass().getSimpleName().endsWith("WinSysTerminal");
- this.root = root;
- this.display = new Display(terminal, true);
- this.bindingReader = new BindingReader(terminal.reader());
- this.size = new Size();
- Attributes attrs = terminal.getAttributes();
- this.vsusp = attrs.getControlChar(ControlChar.VSUSP);
- if (vsusp > 0) {
- attrs.setControlChar(ControlChar.VSUSP, 0);
- terminal.setAttributes(attrs);
- }
- Path nanorc = configPath != null ? configPath.getConfig(DEFAULT_NANORC_FILE) : null;
- boolean ignorercfiles = opts != null && opts.isSet("ignorercfiles");
- if (new File("/usr/share/nano").exists() && !ignorercfiles) {
- PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:/usr/share/nano/*.nanorc");
- try (Stream<Path> pathStream = Files.walk(Paths.get("/usr/share/nano"))) {
- pathStream.filter(pathMatcher::matches).forEach(syntaxFiles::add);
- nanorcIgnoreErrors = true;
- } catch (IOException e) {
- errorMessage = "Encountered error while reading nanorc files";
- }
- }
- if (opts != null) {
- this.restricted = opts.isSet("restricted");
- this.syntaxName = null;
- if (opts.isSet("syntax")) {
- this.syntaxName = opts.get("syntax");
- nanorcIgnoreErrors = false;
- }
- if (opts.isSet("backup")) {
- writeBackup = true;
- }
- if (opts.isSet("quotestr")) {
- quoteStr = opts.get("quotestr");
- }
- if (opts.isSet("tabsize")) {
- tabs = opts.getNumber("tabsize");
- }
- if (opts.isSet("quickblank")) {
- quickBlank = true;
- }
- if (opts.isSet("constantshow")) {
- constantCursor = true;
- }
- if (opts.isSet("emptyline")) {
- oneMoreLine = false;
- }
- if (opts.isSet("jumpyscrolling")) {
- smoothScrolling = false;
- }
- if (opts.isSet("linenumbers")) {
- printLineNumbers = true;
- }
- if (opts.isSet("mouse")) {
- mouseSupport = true;
- }
- if (opts.isSet("softwrap")) {
- wrapping = true;
- }
- if (opts.isSet("atblanks")) {
- atBlanks = true;
- }
- if (opts.isSet("suspend")) {
- enableSuspension();
- }
- if (opts.isSet("view")) {
- view = true;
- }
- if (opts.isSet("cutfromcursor")) {
- cut2end = true;
- }
- if (opts.isSet("tempfile")) {
- tempFile = true;
- }
- if (opts.isSet("historylog")) {
- historyLog = opts.get("historyLog");
- }
- if (opts.isSet("tabstospaces")) {
- tabsToSpaces = true;
- }
- if (opts.isSet("autoindent")) {
- autoIndent = true;
- }
- }
- bindKeys();
- if (configPath != null && historyLog != null) {
- try {
- patternHistory = new PatternHistory(configPath.getUserConfig(historyLog, true));
- } catch (IOException e) {
- errorMessage = "Encountered error while reading pattern-history file: " + historyLog;
- }
- }
- }
-
- public void setRestricted(boolean restricted) {
- this.restricted = restricted;
- }
-
- public void open(String... files) throws IOException {
- open(Arrays.asList(files));
- }
-
- public void open(List<String> files) throws IOException {
- for (String file : files) {
- file = file.startsWith("~") ? file.replace("~", System.getProperty("user.home")) : file;
- if (file.contains("*") || file.contains("?")) {
- for (Path p : findFiles(root, file)) {
- buffers.add(new Buffer(p.toString()));
- }
- } else {
- buffers.add(new Buffer(file));
- }
- }
- }
-
- protected static List<Path> findFiles(Path root, String files) throws IOException {
- files = files.startsWith("~") ? files.replace("~", System.getProperty("user.home")) : files;
- String regex = files;
- Path searchRoot = Paths.get("/");
- if (new File(files).isAbsolute()) {
- regex = regex.replaceAll("\\\\", "/").replaceAll("//", "/");
- if (regex.contains("/")) {
- String sr = regex.substring(0, regex.lastIndexOf("/") + 1);
- while (sr.contains("*") || sr.contains("?")) {
- sr = sr.substring(0, sr.lastIndexOf("/"));
- }
- searchRoot = Paths.get(sr + "/");
- }
- } else {
- regex = (root.toString().length() == 0 ? "" : root + "/") + files;
- regex = regex.replaceAll("\\\\", "/").replaceAll("//", "/");
- searchRoot = root;
- }
- PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + regex);
- try (Stream<Path> pathStream = Files.walk(searchRoot)) {
- return pathStream.filter(pathMatcher::matches).collect(Collectors.toList());
- }
- }
-
- public void run() throws IOException {
- if (buffers.isEmpty()) {
- buffers.add(new Buffer(null));
- }
- buffer = buffers.get(bufferIndex);
-
- Attributes attributes = terminal.getAttributes();
- Attributes newAttr = new Attributes(attributes);
- if (vsusp > 0) {
- attributes.setControlChar(ControlChar.VSUSP, vsusp);
- }
- newAttr.setLocalFlags(EnumSet.of(LocalFlag.ICANON, LocalFlag.ECHO, LocalFlag.IEXTEN, LocalFlag.ISIG), false);
- newAttr.setInputFlags(EnumSet.of(InputFlag.IXON, InputFlag.ICRNL, InputFlag.INLCR), false);
- newAttr.setControlChar(ControlChar.VMIN, 1);
- newAttr.setControlChar(ControlChar.VTIME, 0);
- newAttr.setControlChar(ControlChar.VINTR, 0);
- terminal.setAttributes(newAttr);
- terminal.puts(Capability.enter_ca_mode);
- terminal.puts(Capability.keypad_xmit);
- if (mouseSupport) {
- terminal.trackMouse(Terminal.MouseTracking.Any);
- }
-
- this.shortcuts = standardShortcuts();
-
- SignalHandler prevHandler = null;
- Status status = Status.getStatus(terminal, false);
- try {
- size.copy(terminal.getSize());
- if (status != null) {
- status.suspend();
- }
- buffer.open();
- if (errorMessage != null) {
- setMessage(errorMessage);
- errorMessage = null;
- } else if (buffer.file != null) {
- setMessage("Read " + buffer.lines.size() + " lines");
- }
-
- display.clear();
- display.reset();
- display.resize(size.getRows(), size.getColumns());
- prevHandler = terminal.handle(Signal.WINCH, this::handle);
-
- display();
-
- while (true) {
- Operation op;
- switch (op = readOperation(keys)) {
- case QUIT:
- if (help) {
- resetSuggestion();
- break;
- }
- if (quit()) {
- return;
- }
- break;
- case WRITE:
- write();
- break;
- case READ:
- read();
- break;
- case UP:
- if (help && suggestionBox != null) {
- suggestionBox.up();
- } else {
- buffer.moveUp(1);
- }
- break;
- case DOWN:
- if (help && suggestionBox != null) {
- suggestionBox.down();
- } else {
- buffer.moveDown(1);
- }
- break;
- case LEFT:
- buffer.moveLeft(1);
- if (help) {
- resetSuggestion();
- }
- break;
- case RIGHT:
- buffer.moveRight(1);
- if (help) {
- resetSuggestion();
- }
- break;
- case INSERT:
- if (this.help) {
- this.insertHelp = true;
- } else {
- buffer.insert(bindingReader.getLastBinding());
- }
- break;
- case BACKSPACE:
- buffer.backspace(1);
- break;
- case DELETE:
- buffer.delete(1);
- break;
- case WRAP:
- wrap();
- break;
- case NUMBERS:
- numbers();
- break;
- case SMOOTH_SCROLLING:
- smoothScrolling();
- break;
- case MOUSE_SUPPORT:
- mouseSupport();
- break;
- case ONE_MORE_LINE:
- oneMoreLine();
- break;
- case CLEAR_SCREEN:
- clearScreen();
- break;
- case PREV_BUFFER:
- prevBuffer();
- break;
- case NEXT_BUFFER:
- nextBuffer();
- break;
- case CUR_POS:
- curPos();
- break;
- case LSP_SUGGESTION:
- help = true;
- break;
- case BEGINNING_OF_LINE:
- buffer.beginningOfLine();
- break;
- case END_OF_LINE:
- buffer.endOfLine();
- break;
- case FIRST_LINE:
- buffer.firstLine();
- break;
- case LAST_LINE:
- buffer.lastLine();
- break;
- case PREV_PAGE:
- buffer.prevPage();
- break;
- case NEXT_PAGE:
- buffer.nextPage();
- break;
- case SCROLL_UP:
- buffer.scrollUp(1);
- break;
- case SCROLL_DOWN:
- buffer.scrollDown(1);
- break;
- case SEARCH:
- searchToReplace = false;
- searchAndReplace();
- break;
- case REPLACE:
- searchToReplace = true;
- searchAndReplace();
- break;
- case NEXT_SEARCH:
- buffer.nextSearch();
- break;
- case HELP:
- help("edit-help.txt");
- break;
- case CONSTANT_CURSOR:
- constantCursor();
- break;
- case VERBATIM:
- buffer.insert(new String(Character.toChars(bindingReader.readCharacter())));
- break;
- case MATCHING:
- buffer.matching();
- break;
- case MOUSE_EVENT:
- mouseEvent();
- break;
- case TOGGLE_SUSPENSION:
- toggleSuspension();
- break;
- case COPY:
- buffer.copy();
- break;
- case CUT:
- buffer.cut();
- break;
- case UNCUT:
- buffer.uncut();
- break;
- case GOTO:
- gotoLine();
- curPos();
- break;
- case CUT_TO_END_TOGGLE:
- cut2end = !cut2end;
- setMessage("Cut to end " + (cut2end ? "enabled" : "disabled"));
- break;
- case CUT_TO_END:
- buffer.cut(true);
- break;
- case MARK:
- mark = !mark;
- setMessage("Mark " + (mark ? "Set" : "Unset"));
- buffer.mark();
- break;
- case HIGHLIGHT:
- highlight = !highlight;
- setMessage("Highlight " + (highlight ? "enabled" : "disabled"));
- break;
- case TABS_TO_SPACE:
- tabsToSpaces = !tabsToSpaces;
- setMessage("Conversion of typed tabs to spaces " + (tabsToSpaces ? "enabled" : "disabled"));
- break;
- case AUTO_INDENT:
- autoIndent = !autoIndent;
- setMessage("Auto indent " + (autoIndent ? "enabled" : "disabled"));
- break;
- default:
- setMessage("Unsupported " + op.name().toLowerCase().replace('_', '-'));
- break;
- }
- display();
- }
- } finally {
- if (mouseSupport) {
- terminal.writer().write("\033[?1005l\033[?1003l");
- }
- if (!terminal.puts(Capability.exit_ca_mode)) {
- terminal.puts(Capability.clear_screen);
- }
- terminal.puts(Capability.keypad_local);
- terminal.flush();
- terminal.setAttributes(attributes);
- terminal.handle(Signal.WINCH, prevHandler);
- if (status != null) {
- status.restore();
- }
- patternHistory.persist();
- }
- }
-
- private void resetSuggestion() {
- this.suggestions = null;
- this.documentation = null;
- this.suggestionBox = null;
- this.insertHelp = false;
- this.help = false;
- }
-
- private int editInputBuffer(Operation operation, int curPos) {
- switch (operation) {
- case INSERT:
- editBuffer.insert(curPos++, bindingReader.getLastBinding());
- break;
- case BACKSPACE:
- if (curPos > 0) {
- editBuffer.deleteCharAt(--curPos);
- }
- break;
- case LEFT:
- if (curPos > 0) {
- curPos--;
- }
- break;
- case RIGHT:
- if (curPos < editBuffer.length()) {
- curPos++;
- }
- break;
- }
- return curPos;
- }
-
- boolean write() throws IOException {
- KeyMap<Operation> writeKeyMap = new KeyMap<>();
- if (!restricted) {
- writeKeyMap.setUnicode(Operation.INSERT);
- for (char i = 32; i < 256; i++) {
- writeKeyMap.bind(Operation.INSERT, Character.toString(i));
- }
- for (char i = 'A'; i <= 'Z'; i++) {
- writeKeyMap.bind(Operation.DO_LOWER_CASE, alt(i));
- }
- writeKeyMap.bind(Operation.BACKSPACE, del());
- writeKeyMap.bind(Operation.APPEND_MODE, alt('a'));
- writeKeyMap.bind(Operation.PREPEND_MODE, alt('p'));
- writeKeyMap.bind(Operation.BACKUP, alt('b'));
- writeKeyMap.bind(Operation.TO_FILES, ctrl('T'));
- }
- writeKeyMap.bind(Operation.MAC_FORMAT, alt('m'));
- writeKeyMap.bind(Operation.DOS_FORMAT, alt('d'));
- writeKeyMap.bind(Operation.ACCEPT, "\r");
- writeKeyMap.bind(Operation.CANCEL, ctrl('C'));
- writeKeyMap.bind(Operation.HELP, ctrl('G'), key(terminal, Capability.key_f1));
- writeKeyMap.bind(Operation.MOUSE_EVENT, key(terminal, Capability.key_mouse));
- writeKeyMap.bind(Operation.TOGGLE_SUSPENSION, alt('z'));
- writeKeyMap.bind(Operation.RIGHT, key(terminal, Capability.key_right));
- writeKeyMap.bind(Operation.LEFT, key(terminal, Capability.key_left));
-
- editMessage = getWriteMessage();
- editBuffer.setLength(0);
- editBuffer.append(buffer.file == null ? "" : buffer.file);
- int curPos = editBuffer.length();
- this.shortcuts = writeShortcuts();
- display(curPos);
- while (true) {
- Operation op = readOperation(writeKeyMap);
- switch (op) {
- case CANCEL:
- editMessage = null;
- this.shortcuts = standardShortcuts();
- return false;
- case ACCEPT:
- editMessage = null;
- if (save(editBuffer.toString())) {
- this.shortcuts = standardShortcuts();
- return true;
- }
- return false;
- case HELP:
- help("/org/jline/builtins/nano-write-help.txt");
- break;
- case MAC_FORMAT:
- buffer.format = (buffer.format == WriteFormat.MAC) ? WriteFormat.UNIX : WriteFormat.MAC;
- break;
- case DOS_FORMAT:
- buffer.format = (buffer.format == WriteFormat.DOS) ? WriteFormat.UNIX : WriteFormat.DOS;
- break;
- case APPEND_MODE:
- writeMode = (writeMode == WriteMode.APPEND) ? WriteMode.WRITE : WriteMode.APPEND;
- break;
- case PREPEND_MODE:
- writeMode = (writeMode == WriteMode.PREPEND) ? WriteMode.WRITE : WriteMode.PREPEND;
- break;
- case BACKUP:
- writeBackup = !writeBackup;
- break;
- case MOUSE_EVENT:
- mouseEvent();
- break;
- case TOGGLE_SUSPENSION:
- toggleSuspension();
- break;
- default:
- curPos = editInputBuffer(op, curPos);
- break;
- }
- editMessage = getWriteMessage();
- display(curPos);
- }
- }
-
- private Operation readOperation(KeyMap<Operation> keymap) {
- while (true) {
- Operation op = bindingReader.readBinding(keymap);
- if (op == Operation.DO_LOWER_CASE) {
- bindingReader.runMacro(bindingReader.getLastBinding().toLowerCase());
- } else {
- return op;
- }
- }
- }
-
- private boolean save(String name) throws IOException {
- Path orgPath = buffer.file != null ? root.resolve(buffer.file) : null;
- Path newPath = root.resolve(name);
- boolean isSame
- = orgPath != null && Files.exists(orgPath) && Files.exists(newPath) && Files.isSameFile(orgPath, newPath);
- if (!isSame && Files.exists(Paths.get(name)) && writeMode == WriteMode.WRITE) {
- Operation op = getYNC("File exists, OVERWRITE ? ");
- if (op != Operation.YES) {
- return false;
- }
- } else if (!Files.exists(newPath)) {
- Files.createFile(newPath);
- }
- Path t = Files.createTempFile("jline-", ".temp");
- try (OutputStream os = Files.newOutputStream(
- t, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) {
- if (writeMode == WriteMode.APPEND) {
- if (Files.isReadable(newPath)) {
- Files.copy(newPath, os);
- }
- }
- Writer w = new OutputStreamWriter(os, buffer.charset);
- for (int i = 0; i < buffer.lines.size(); i++) {
- w.write(buffer.lines.get(i));
- switch (buffer.format) {
- case UNIX:
- w.write("\n");
- break;
- case DOS:
- w.write("\r\n");
- break;
- case MAC:
- w.write("\r");
- break;
- }
- }
- w.flush();
- if (writeMode == WriteMode.PREPEND) {
- if (Files.isReadable(newPath)) {
- Files.copy(newPath, os);
- }
- }
- if (writeBackup) {
- Files.move(
- newPath,
- newPath.resolveSibling(newPath.getFileName().toString() + "~"),
- StandardCopyOption.REPLACE_EXISTING);
- }
- Files.move(t, newPath, StandardCopyOption.REPLACE_EXISTING);
- if (writeMode == WriteMode.WRITE) {
- buffer.file = name;
- buffer.dirty = false;
- }
- setMessage("Wrote " + buffer.lines.size() + " lines");
- return true;
- } catch (IOException e) {
- setMessage("Error writing " + name + ": " + e);
- return false;
- } finally {
- Files.deleteIfExists(t);
- writeMode = WriteMode.WRITE;
- }
- }
-
- private Operation getYNC(String message) {
- return getYNC(message, false);
- }
-
- private Operation getYNC(String message, boolean andAll) {
- String oldEditMessage = editMessage;
- String oldEditBuffer = editBuffer.toString();
- LinkedHashMap<String, String> oldShortcuts = shortcuts;
- try {
- editMessage = message;
- editBuffer.setLength(0);
- KeyMap<Operation> yncKeyMap = new KeyMap<>();
- yncKeyMap.bind(Operation.YES, "y", "Y");
- if (andAll) {
- yncKeyMap.bind(Operation.ALL, "a", "A");
- }
- yncKeyMap.bind(Operation.NO, "n", "N");
- yncKeyMap.bind(Operation.CANCEL, ctrl('C'));
- shortcuts = new LinkedHashMap<>();
- shortcuts.put(" Y", "Yes");
- if (andAll) {
- shortcuts.put(" A", "All");
- }
- shortcuts.put(" N", "No");
- shortcuts.put("^C", "Cancel");
- display();
- return readOperation(yncKeyMap);
- } finally {
- editMessage = oldEditMessage;
- editBuffer.append(oldEditBuffer);
- shortcuts = oldShortcuts;
- }
- }
-
- private String getWriteMessage() {
- StringBuilder sb = new StringBuilder();
- sb.append("File Name to ");
- switch (writeMode) {
- case WRITE:
- sb.append("Write");
- break;
- case APPEND:
- sb.append("Append");
- break;
- case PREPEND:
- sb.append("Prepend");
- break;
- }
- switch (buffer.format) {
- case UNIX:
- break;
- case DOS:
- sb.append(" [DOS Format]");
- break;
- case MAC:
- sb.append(" [Mac Format]");
- break;
- }
- if (writeBackup) {
- sb.append(" [Backup]");
- }
- sb.append(": ");
- return sb.toString();
- }
-
- void read() {
- KeyMap<Operation> readKeyMap = new KeyMap<>();
- readKeyMap.setUnicode(Operation.INSERT);
- for (char i = 32; i < 256; i++) {
- readKeyMap.bind(Operation.INSERT, Character.toString(i));
- }
- for (char i = 'A'; i <= 'Z'; i++) {
- readKeyMap.bind(Operation.DO_LOWER_CASE, alt(i));
- }
- readKeyMap.bind(Operation.BACKSPACE, del());
- readKeyMap.bind(Operation.NEW_BUFFER, alt('f'));
- readKeyMap.bind(Operation.TO_FILES, ctrl('T'));
- readKeyMap.bind(Operation.EXECUTE, ctrl('X'));
- readKeyMap.bind(Operation.ACCEPT, "\r");
- readKeyMap.bind(Operation.CANCEL, ctrl('C'));
- readKeyMap.bind(Operation.HELP, ctrl('G'), key(terminal, Capability.key_f1));
- readKeyMap.bind(Operation.MOUSE_EVENT, key(terminal, Capability.key_mouse));
- readKeyMap.bind(Operation.RIGHT, key(terminal, Capability.key_right));
- readKeyMap.bind(Operation.LEFT, key(terminal, Capability.key_left));
-
- editMessage = getReadMessage();
- editBuffer.setLength(0);
- int curPos = editBuffer.length();
- this.shortcuts = readShortcuts();
- display(curPos);
- while (true) {
- Operation op = readOperation(readKeyMap);
- switch (op) {
- case CANCEL:
- editMessage = null;
- this.shortcuts = standardShortcuts();
- return;
- case ACCEPT:
- editMessage = null;
- String file = editBuffer.toString();
- boolean empty = file.isEmpty();
- Path p = empty ? null : root.resolve(file);
- if (!readNewBuffer && !empty && !Files.exists(p)) {
- setMessage("\"" + file + "\" not found");
- } else if (!empty && Files.isDirectory(p)) {
- setMessage("\"" + file + "\" is a directory");
- } else if (!empty && !Files.isRegularFile(p)) {
- setMessage("\"" + file + "\" is not a regular file");
- } else {
- Buffer buf = new Buffer(empty ? null : file);
- try {
- buf.open();
- if (readNewBuffer) {
- buffers.add(++bufferIndex, buf);
- buffer = buf;
- } else {
- buffer.insert(String.join("\n", buf.lines));
- }
- setMessage(null);
- } catch (IOException e) {
- setMessage("Error reading " + file + ": " + e.getMessage());
- }
- }
- this.shortcuts = standardShortcuts();
- return;
- case HELP:
- help("/org/jline/builtins/nano-read-help.txt");
- break;
- case NEW_BUFFER:
- readNewBuffer = !readNewBuffer;
- break;
- case MOUSE_EVENT:
- mouseEvent();
- break;
- default:
- curPos = editInputBuffer(op, curPos);
- break;
- }
- editMessage = getReadMessage();
- display(curPos);
- }
- }
-
- private String getReadMessage() {
- StringBuilder sb = new StringBuilder();
- sb.append("File to insert");
- if (readNewBuffer) {
- sb.append(" into new buffer");
- }
- sb.append(" [from ./]: ");
- return sb.toString();
- }
-
- void gotoLine() {
- KeyMap<Operation> readKeyMap = new KeyMap<>();
- readKeyMap.setUnicode(Operation.INSERT);
- for (char i = 32; i < 256; i++) {
- readKeyMap.bind(Operation.INSERT, Character.toString(i));
- }
- readKeyMap.bind(Operation.BACKSPACE, del());
- readKeyMap.bind(Operation.ACCEPT, "\r");
- readKeyMap.bind(Operation.HELP, ctrl('G'), key(terminal, Capability.key_f1));
- readKeyMap.bind(Operation.CANCEL, ctrl('C'));
- readKeyMap.bind(Operation.RIGHT, key(terminal, Capability.key_right));
- readKeyMap.bind(Operation.LEFT, key(terminal, Capability.key_left));
- readKeyMap.bind(Operation.FIRST_LINE, ctrl('Y'));
- readKeyMap.bind(Operation.LAST_LINE, ctrl('V'));
- readKeyMap.bind(Operation.SEARCH, ctrl('T'));
-
- editMessage = "Enter line number, column number: ";
- editBuffer.setLength(0);
- int curPos = editBuffer.length();
- this.shortcuts = gotoShortcuts();
- display(curPos);
- while (true) {
- Operation op = readOperation(readKeyMap);
- switch (op) {
- case CANCEL:
- editMessage = null;
- this.shortcuts = standardShortcuts();
- return;
- case FIRST_LINE:
- editMessage = null;
- buffer.firstLine();
- this.shortcuts = standardShortcuts();
- return;
- case LAST_LINE:
- editMessage = null;
- buffer.lastLine();
- this.shortcuts = standardShortcuts();
- return;
- case SEARCH:
- searchToReplace = false;
- searchAndReplace();
- return;
- case ACCEPT:
- editMessage = null;
- String[] pos = editBuffer.toString().split(",", 2);
- int[] args = { 0, 0 };
- try {
- for (int i = 0; i < pos.length; i++) {
- if (!pos[i].trim().isEmpty()) {
- args[i] = Integer.parseInt(pos[i]) - 1;
- if (args[i] < 0) {
- throw new NumberFormatException();
- }
- }
- }
- buffer.gotoLine(args[1], args[0]);
- } catch (NumberFormatException ex) {
- setMessage("Invalid line or column number");
- } catch (Exception ex) {
- setMessage("Internal error: " + ex.getMessage());
- }
- this.shortcuts = standardShortcuts();
- return;
- case HELP:
- help("/org/jline/builtins/nano-goto-help.txt");
- break;
- default:
- curPos = editInputBuffer(op, curPos);
- break;
- }
- display(curPos);
- }
- }
-
- private LinkedHashMap<String, String> gotoShortcuts() {
- LinkedHashMap<String, String> shortcuts = new LinkedHashMap<>();
- shortcuts.put("^G", "Get Help");
- shortcuts.put("^Y", "First Line");
- shortcuts.put("^T", "Go To Text");
- shortcuts.put("^C", "Cancel");
- shortcuts.put("^V", "Last Line");
- return shortcuts;
- }
-
- private LinkedHashMap<String, String> readShortcuts() {
- LinkedHashMap<String, String> shortcuts = new LinkedHashMap<>();
- shortcuts.put("^G", "Get Help");
- shortcuts.put("^T", "To Files");
- shortcuts.put("M-F", "New Buffer");
- shortcuts.put("^C", "Cancel");
- shortcuts.put("^X", "Execute Command");
- return shortcuts;
- }
-
- private LinkedHashMap<String, String> writeShortcuts() {
- LinkedHashMap<String, String> s = new LinkedHashMap<>();
- s.put("^G", "Get Help");
- s.put("M-M", "Mac Format");
- s.put("^C", "Cancel");
- s.put("M-D", "DOS Format");
- if (!restricted) {
- s.put("^T", "To Files");
- s.put("M-P", "Prepend");
- s.put("M-A", "Append");
- s.put("M-B", "Backup File");
- }
- return s;
- }
-
- private LinkedHashMap<String, String> helpShortcuts() {
- LinkedHashMap<String, String> s = new LinkedHashMap<>();
- s.put("^L", "Refresh");
- s.put("^Y", "Prev Page");
- s.put("^P", "Prev Line");
- s.put("M-\\", "First Line");
- s.put("^X", "Exit");
- s.put("^V", "Next Page");
- s.put("^N", "Next Line");
- s.put("M-/", "Last Line");
- return s;
- }
-
- private LinkedHashMap<String, String> searchShortcuts() {
- LinkedHashMap<String, String> s = new LinkedHashMap<>();
- s.put("^G", "Get Help");
- s.put("^Y", "First Line");
- if (searchToReplace) {
- s.put("^R", "No Replace");
- } else {
- s.put("^R", "Replace");
- s.put("^W", "Beg of Par");
- }
- s.put("M-C", "Case Sens");
- s.put("M-R", "Regexp");
- s.put("^C", "Cancel");
- s.put("^V", "Last Line");
- s.put("^T", "Go To Line");
- if (!searchToReplace) {
- s.put("^O", "End of Par");
- }
- s.put("M-B", "Backwards");
- s.put("^P", "PrevHstory");
- return s;
- }
-
- private LinkedHashMap<String, String> replaceShortcuts() {
- LinkedHashMap<String, String> s = new LinkedHashMap<>();
- s.put("^G", "Get Help");
- s.put("^Y", "First Line");
- s.put("^P", "PrevHstory");
- s.put("^C", "Cancel");
- s.put("^V", "Last Line");
- s.put("^N", "NextHstory");
- return s;
- }
-
- private LinkedHashMap<String, String> standardShortcuts() {
- LinkedHashMap<String, String> s = new LinkedHashMap<>();
- s.put("^G", "Get Help");
- if (!view) {
- s.put("^O", "WriteOut");
- }
- s.put("^R", "Read File");
- s.put("^Y", "Prev Page");
- if (!view) {
- s.put("^K", "Cut Text");
- }
- s.put("^C", "Cur Pos");
- s.put("^X", "Exit");
- if (!view) {
- s.put("^J", "Justify");
- }
- s.put("^W", "Where Is");
- s.put("^V", "Next Page");
- if (!view) {
- s.put("^U", "UnCut Text");
- }
- s.put("^T", "To Spell");
- return s;
- }
-
- void help(String help) {
- Buffer org = this.buffer;
- Buffer newBuf = new Buffer("");
- try (InputStream is = getClass().getResourceAsStream(help)) {
- newBuf.open(is);
- } catch (IOException e) {
- setMessage("Unable to read help");
- return;
- }
- LinkedHashMap<String, String> oldShortcuts = this.shortcuts;
- this.shortcuts = helpShortcuts();
- boolean oldWrapping = this.wrapping;
- boolean oldPrintLineNumbers = this.printLineNumbers;
- boolean oldConstantCursor = this.constantCursor;
- boolean oldAtBlanks = this.atBlanks;
- boolean oldHighlight = this.highlight;
- String oldEditMessage = this.editMessage;
- this.editMessage = "";
- this.wrapping = true;
- this.atBlanks = true;
- this.printLineNumbers = false;
- this.constantCursor = false;
- this.highlight = false;
- this.buffer = newBuf;
- if (!oldWrapping) {
- buffer.computeAllOffsets();
- }
- try {
- this.message = null;
- terminal.puts(Capability.cursor_invisible);
- display();
- while (true) {
- switch (readOperation(keys)) {
- case QUIT:
- return;
- case FIRST_LINE:
- buffer.firstLine();
- break;
- case LAST_LINE:
- buffer.lastLine();
- break;
- case PREV_PAGE:
- buffer.prevPage();
- break;
- case NEXT_PAGE:
- buffer.nextPage();
- break;
- case UP:
- buffer.scrollUp(1);
- break;
- case DOWN:
- buffer.scrollDown(1);
- break;
- case CLEAR_SCREEN:
- clearScreen();
- break;
- case MOUSE_EVENT:
- mouseEvent();
- break;
- case TOGGLE_SUSPENSION:
- toggleSuspension();
- break;
- }
- display();
- }
- } finally {
- this.buffer = org;
- this.wrapping = oldWrapping;
- this.printLineNumbers = oldPrintLineNumbers;
- this.constantCursor = oldConstantCursor;
- this.shortcuts = oldShortcuts;
- this.atBlanks = oldAtBlanks;
- this.highlight = oldHighlight;
- this.editMessage = oldEditMessage;
- terminal.puts(Capability.cursor_visible);
- if (!oldWrapping) {
- buffer.computeAllOffsets();
- }
- }
- }
-
- void searchAndReplace() {
- try {
- search();
- if (!searchToReplace) {
- return;
- }
- String replaceTerm = replace();
- int replaced = 0;
- boolean all = false;
- boolean found = true;
- List<Integer> matches = new ArrayList<>();
- Operation op = Operation.NO;
- while (found) {
- found = buffer.nextSearch();
- if (found) {
- int[] re = buffer.highlightStart();
- int col = searchBackwards ? buffer.length(buffer.getLine(re[0])) - re[1] : re[1];
- int match = re[0] * 10000 + col;
- if (matches.contains(match)) {
- break;
- } else {
- matches.add(match);
- }
- if (!all) {
- op = getYNC("Replace this instance? ", true);
- }
- } else {
- op = Operation.NO;
- }
- switch (op) {
- case ALL:
- all = true;
- buffer.replaceFromCursor(matchedLength, replaceTerm);
- replaced++;
- break;
- case YES:
- buffer.replaceFromCursor(matchedLength, replaceTerm);
- replaced++;
- break;
- case NO:
- break;
- case CANCEL:
- found = false;
- break;
- default:
- break;
- }
- }
- message = "Replaced " + replaced + " occurrences";
- } catch (Exception e) {
- // ignore
- } finally {
- searchToReplace = false;
- matchedLength = -1;
- this.shortcuts = standardShortcuts();
- editMessage = null;
- }
- }
-
- void search() throws IOException {
- KeyMap<Operation> searchKeyMap = new KeyMap<>();
- searchKeyMap.setUnicode(Operation.INSERT);
- // searchKeyMap.setNomatch(Operation.INSERT);
- for (char i = 32; i < 256; i++) {
- searchKeyMap.bind(Operation.INSERT, Character.toString(i));
- }
- for (char i = 'A'; i <= 'Z'; i++) {
- searchKeyMap.bind(Operation.DO_LOWER_CASE, alt(i));
- }
- searchKeyMap.bind(Operation.BACKSPACE, del());
- searchKeyMap.bind(Operation.CASE_SENSITIVE, alt('c'));
- searchKeyMap.bind(Operation.BACKWARDS, alt('b'));
- searchKeyMap.bind(Operation.REGEXP, alt('r'));
- searchKeyMap.bind(Operation.ACCEPT, "\r");
- searchKeyMap.bind(Operation.CANCEL, ctrl('C'));
- searchKeyMap.bind(Operation.HELP, ctrl('G'), key(terminal, Capability.key_f1));
- searchKeyMap.bind(Operation.FIRST_LINE, ctrl('Y'));
- searchKeyMap.bind(Operation.LAST_LINE, ctrl('V'));
- searchKeyMap.bind(Operation.MOUSE_EVENT, key(terminal, Capability.key_mouse));
- searchKeyMap.bind(Operation.RIGHT, key(terminal, Capability.key_right));
- searchKeyMap.bind(Operation.LEFT, key(terminal, Capability.key_left));
- searchKeyMap.bind(Operation.UP, key(terminal, Capability.key_up));
- searchKeyMap.bind(Operation.DOWN, key(terminal, Capability.key_down));
- searchKeyMap.bind(Operation.TOGGLE_REPLACE, ctrl('R'));
-
- editMessage = getSearchMessage();
- editBuffer.setLength(0);
- String currentBuffer = editBuffer.toString();
- int curPos = editBuffer.length();
- this.shortcuts = searchShortcuts();
- display(curPos);
- try {
- while (true) {
- Operation op = readOperation(searchKeyMap);
- switch (op) {
- case UP:
- editBuffer.setLength(0);
- editBuffer.append(patternHistory.up(currentBuffer));
- curPos = editBuffer.length();
- break;
- case DOWN:
- editBuffer.setLength(0);
- editBuffer.append(patternHistory.down(currentBuffer));
- curPos = editBuffer.length();
- break;
- case CASE_SENSITIVE:
- searchCaseSensitive = !searchCaseSensitive;
- break;
- case BACKWARDS:
- searchBackwards = !searchBackwards;
- break;
- case REGEXP:
- searchRegexp = !searchRegexp;
- break;
- case CANCEL:
- throw new IllegalArgumentException();
- case ACCEPT:
- if (editBuffer.length() > 0) {
- searchTerm = editBuffer.toString();
- }
- if (searchTerm == null || searchTerm.isEmpty()) {
- setMessage("Cancelled");
- throw new IllegalArgumentException();
- } else {
- patternHistory.add(searchTerm);
- if (!searchToReplace) {
- buffer.nextSearch();
- }
- }
- return;
- case HELP:
- if (searchToReplace) {
- help("/org/jline/builtins/nano-search-replace-help.txt");
- } else {
- help("/org/jline/builtins/nano-search-help.txt");
- }
- break;
- case FIRST_LINE:
- buffer.firstLine();
- break;
- case LAST_LINE:
- buffer.lastLine();
- break;
- case MOUSE_EVENT:
- mouseEvent();
- break;
- case TOGGLE_REPLACE:
- searchToReplace = !searchToReplace;
- this.shortcuts = searchShortcuts();
- break;
- default:
- curPos = editInputBuffer(op, curPos);
- currentBuffer = editBuffer.toString();
- break;
- }
- editMessage = getSearchMessage();
- display(curPos);
- }
- } finally {
- this.shortcuts = standardShortcuts();
- editMessage = null;
- }
- }
-
- String replace() throws IOException {
- KeyMap<Operation> keyMap = new KeyMap<>();
- keyMap.setUnicode(Operation.INSERT);
- // keyMap.setNomatch(Operation.INSERT);
- for (char i = 32; i < 256; i++) {
- keyMap.bind(Operation.INSERT, Character.toString(i));
- }
- for (char i = 'A'; i <= 'Z'; i++) {
- keyMap.bind(Operation.DO_LOWER_CASE, alt(i));
- }
- keyMap.bind(Operation.BACKSPACE, del());
- keyMap.bind(Operation.ACCEPT, "\r");
- keyMap.bind(Operation.CANCEL, ctrl('C'));
- keyMap.bind(Operation.HELP, ctrl('G'), key(terminal, Capability.key_f1));
- keyMap.bind(Operation.FIRST_LINE, ctrl('Y'));
- keyMap.bind(Operation.LAST_LINE, ctrl('V'));
- keyMap.bind(Operation.RIGHT, key(terminal, Capability.key_right));
- keyMap.bind(Operation.LEFT, key(terminal, Capability.key_left));
- keyMap.bind(Operation.UP, key(terminal, Capability.key_up));
- keyMap.bind(Operation.DOWN, key(terminal, Capability.key_down));
-
- editMessage = "Replace with: ";
- editBuffer.setLength(0);
- String currentBuffer = editBuffer.toString();
- int curPos = editBuffer.length();
- this.shortcuts = replaceShortcuts();
- display(curPos);
- try {
- while (true) {
- Operation op = readOperation(keyMap);
- switch (op) {
- case UP:
- editBuffer.setLength(0);
- editBuffer.append(patternHistory.up(currentBuffer));
- curPos = editBuffer.length();
- break;
- case DOWN:
- editBuffer.setLength(0);
- editBuffer.append(patternHistory.down(currentBuffer));
- curPos = editBuffer.length();
- break;
- case CANCEL:
- throw new IllegalArgumentException();
- case ACCEPT:
- String replaceTerm = "";
- if (editBuffer.length() > 0) {
- replaceTerm = editBuffer.toString();
- }
- patternHistory.add(replaceTerm);
- return replaceTerm;
- case HELP:
- help("/org/jline/builtins/nano-replace-help.txt");
- break;
- case FIRST_LINE:
- buffer.firstLine();
- break;
- case LAST_LINE:
- buffer.lastLine();
- break;
- case MOUSE_EVENT:
- mouseEvent();
- break;
- default:
- curPos = editInputBuffer(op, curPos);
- currentBuffer = editBuffer.toString();
- break;
- }
- display(curPos);
- }
- } finally {
- this.shortcuts = standardShortcuts();
- editMessage = null;
- }
- }
-
- private String getSearchMessage() {
- StringBuilder sb = new StringBuilder();
- sb.append("Search");
- if (searchToReplace) {
- sb.append(" (to replace)");
- }
- if (searchCaseSensitive) {
- sb.append(" [Case Sensitive]");
- }
- if (searchRegexp) {
- sb.append(" [Regexp]");
- }
- if (searchBackwards) {
- sb.append(" [Backwards]");
- }
- if (searchTerm != null) {
- sb.append(" [");
- sb.append(searchTerm);
- sb.append("]");
- }
- sb.append(": ");
- return sb.toString();
- }
-
- String computeCurPos() {
- int chari = 0;
- int chart = 0;
- for (int i = 0; i < buffer.lines.size(); i++) {
- int l = buffer.lines.get(i).length() + 1;
- if (i < buffer.line) {
- chari += l;
- } else if (i == buffer.line) {
- chari += buffer.offsetInLine + buffer.column;
- }
- chart += l;
- }
-
- StringBuilder sb = new StringBuilder();
- sb.append("line ");
- sb.append(buffer.line + 1);
- sb.append("/");
- sb.append(buffer.lines.size());
- sb.append(" (");
- sb.append(Math.round((100.0 * buffer.line) / buffer.lines.size()));
- sb.append("%), ");
- sb.append("col ");
- sb.append(buffer.offsetInLine + buffer.column + 1);
- sb.append("/");
- sb.append(buffer.length(buffer.lines.get(buffer.line)) + 1);
- sb.append(" (");
- if (!buffer.lines.get(buffer.line).isEmpty()) {
- sb.append(Math.round(
- (100.0 * (buffer.offsetInLine + buffer.column)) / (buffer.length(buffer.lines.get(buffer.line)))));
- } else {
- sb.append("100");
- }
- sb.append("%), ");
- sb.append("char ");
- sb.append(chari + 1);
- sb.append("/");
- sb.append(chart);
- sb.append(" (");
- sb.append(Math.round((100.0 * chari) / chart));
- sb.append("%)");
- return sb.toString();
- }
-
- void curPos() {
- setMessage(computeCurPos());
- }
-
- void prevBuffer() throws IOException {
- if (buffers.size() > 1) {
- bufferIndex = (bufferIndex + buffers.size() - 1) % buffers.size();
- buffer = buffers.get(bufferIndex);
- setMessage("Switched to " + buffer.getTitle());
- buffer.open();
- display.clear();
- } else {
- setMessage("No more open file buffers");
- }
- }
-
- void nextBuffer() throws IOException {
- if (buffers.size() > 1) {
- bufferIndex = (bufferIndex + 1) % buffers.size();
- buffer = buffers.get(bufferIndex);
- setMessage("Switched to " + buffer.getTitle());
- buffer.open();
- display.clear();
- } else {
- setMessage("No more open file buffers");
- }
- }
-
- void setMessage(String message) {
- this.message = message;
- this.nbBindings = quickBlank ? 2 : 25;
- }
-
- boolean quit() throws IOException {
- if (buffer.dirty) {
- if (tempFile) {
- if (!write()) {
- return false;
- }
- } else {
- Operation op = getYNC("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? ");
- switch (op) {
- case CANCEL:
- return false;
- case NO:
- break;
- case YES:
- if (!write()) {
- return false;
- }
- }
- }
- }
- buffers.remove(bufferIndex);
- if (bufferIndex == buffers.size() && bufferIndex > 0) {
- bufferIndex = buffers.size() - 1;
- }
- if (buffers.isEmpty()) {
- buffer = null;
- return true;
- } else {
- buffer = buffers.get(bufferIndex);
- buffer.open();
- display.clear();
- setMessage("Switched to " + buffer.getTitle());
- return false;
- }
- }
-
- void numbers() {
- printLineNumbers = !printLineNumbers;
- resetDisplay();
- setMessage("Lines numbering " + (printLineNumbers ? "enabled" : "disabled"));
- }
-
- void smoothScrolling() {
- smoothScrolling = !smoothScrolling;
- setMessage("Smooth scrolling " + (smoothScrolling ? "enabled" : "disabled"));
- }
-
- void mouseSupport() {
- mouseSupport = !mouseSupport;
- setMessage("Mouse support " + (mouseSupport ? "enabled" : "disabled"));
- terminal.trackMouse(mouseSupport ? Terminal.MouseTracking.Normal : Terminal.MouseTracking.Off);
- }
-
- void constantCursor() {
- constantCursor = !constantCursor;
- setMessage("Constant cursor position display " + (constantCursor ? "enabled" : "disabled"));
- }
-
- void oneMoreLine() {
- oneMoreLine = !oneMoreLine;
- setMessage("Use of one more line for editing " + (oneMoreLine ? "enabled" : "disabled"));
- }
-
- void wrap() {
- wrapping = !wrapping;
- buffer.computeAllOffsets();
- resetDisplay();
- setMessage("Lines wrapping " + (wrapping ? "enabled" : "disabled"));
- }
-
- void clearScreen() {
- resetDisplay();
- }
-
- void mouseEvent() {
- MouseEvent event = terminal.readMouseEvent();
- if (event.getModifiers().isEmpty()
- && event.getType() == MouseEvent.Type.Released
- && event.getButton() == MouseEvent.Button.Button1) {
- int x = event.getX();
- int y = event.getY();
- int hdr = buffer.computeHeader().size();
- int ftr = computeFooter().size();
- if (y < hdr) {
- // nothing
- } else if (y < size.getRows() - ftr) {
- buffer.moveTo(x, y - hdr);
- } else {
- int cols = (shortcuts.size() + 1) / 2;
- int cw = size.getColumns() / cols;
- int l = y - (size.getRows() - ftr) - 1;
- int si = l * cols + x / cw;
- String shortcut = null;
- Iterator<String> it = shortcuts.keySet().iterator();
- while (si-- >= 0 && it.hasNext()) {
- shortcut = it.next();
- }
- if (shortcut != null) {
- shortcut = shortcut.replaceAll("M-", "\\\\E");
- String seq = KeyMap.translate(shortcut);
- bindingReader.runMacro(seq);
- }
- }
- } else if (event.getType() == MouseEvent.Type.Wheel) {
- if (event.getButton() == MouseEvent.Button.WheelDown) {
- buffer.moveDown(1);
- } else if (event.getButton() == MouseEvent.Button.WheelUp) {
- buffer.moveUp(1);
- }
- } else if (event.getType() == MouseEvent.Type.Moved) {
- this.mouseX = event.getX();
- this.mouseY = event.getY();
- }
- }
-
- void enableSuspension() {
- if (!restricted && vsusp < 0) {
- Attributes attrs = terminal.getAttributes();
- attrs.setControlChar(ControlChar.VSUSP, vsusp);
- terminal.setAttributes(attrs);
- }
- }
-
- void toggleSuspension() {
- if (restricted) {
- setMessage("This function is disabled in restricted mode");
- } else if (vsusp < 0) {
- setMessage("This function is disabled");
- } else {
- Attributes attrs = terminal.getAttributes();
- int toggle = vsusp;
- String message = "enabled";
- if (attrs.getControlChar(ControlChar.VSUSP) > 0) {
- toggle = 0;
- message = "disabled";
- }
- attrs.setControlChar(ControlChar.VSUSP, toggle);
- terminal.setAttributes(attrs);
- setMessage("Suspension " + message);
- }
- }
+public class CamelNanoLspEditor extends Nano {
+ private final LocalCamelDocumentService camelDocumentService = new LocalCamelDocumentService();
- public String getTitle() {
- return title;
+ public CamelNanoLspEditor(Terminal terminal, Path root, Options opts) {
+ this(terminal, root, opts, null);
}
- void resetDisplay() {
- display.clear();
- display.resize(size.getRows(), size.getColumns());
- for (Buffer buffer : buffers) {
- buffer.resetDisplay();
- }
+ public CamelNanoLspEditor(Terminal terminal, Path root, Options opts, ConfigurationPath configPath) {
+ super(terminal, root, opts, configPath);
+ mouseSupport = true;
}
- synchronized void display() {
- display(null);
+ @Override
+ protected List<Diagnostic> computeDiagnostic() {
+ String fileName = buffer.getFile();
+ String text = String.join("\n", this.buffer.getLines()) + "\n";
+ TextDocumentItem textDocumentItem = new TextDocumentItem(fileName, CamelLanguageServer.LANGUAGE_ID, 0, text);
+ return camelDocumentService.computeDiagnostic(textDocumentItem);
}
- synchronized void display(final Integer editCursor) {
- if (nbBindings > 0) {
- if (--nbBindings == 0) {
- message = null;
- }
- }
-
- List<AttributedString> header = buffer.computeHeader();
- List<AttributedString> footer = computeFooter();
-
- int nbLines = size.getRows() - header.size() - footer.size();
- if (insertHelp) {
- insertHelp();
- resetSuggestion();
- }
- String fileName = buffer.file;
+ @Override
+ protected LinkedHashMap<AttributedString, List<AttributedString>> computeSuggestions() {
+ LinkedHashMap<AttributedString, List<AttributedString>> suggestions = new LinkedHashMap<>();
+ String fileName = buffer.getFile();
StringBuilder text = new StringBuilder();
- for (String line : this.buffer.lines) {
+ for (String line : this.buffer.getLines()) {
text.append(line);
text.append('\n');
}
TextDocumentItem textDocumentItem = new TextDocumentItem(fileName, CamelLanguageServer.LANGUAGE_ID, 0, text.toString());
- List<Diagnostic> diagnostics = camelDocumentService.computeDiagnostic(textDocumentItem);
- List<AttributedString> newLines = buffer.getDisplayedLines(nbLines, diagnostics);
- if (help) {
- showCompletion(newLines);
- }
- newLines.addAll(0, header);
- newLines.addAll(footer);
-
- // Compute cursor position
- int cursor;
- if (editMessage != null) {
- int crsr = editCursor != null ? editCursor : editBuffer.length();
- cursor = editMessage.length() + crsr;
- cursor = size.cursorPos(size.getRows() - footer.size(), cursor);
- } else {
- cursor = size.cursorPos(header.size(), buffer.getDisplayedCursor());
+ CompletableFuture<Either<List<CompletionItem>, CompletionList>> eitherCompletableFuture = this.camelDocumentService
+ .completionLocal(textDocumentItem,
+ new Position(buffer.getLine(), buffer.getOffsetInLine() + buffer.getColumn()));
+ if (eitherCompletableFuture.isCompletedExceptionally()) {
+ return suggestions;
}
- display.update(newLines, cursor);
- if (windowsTerminal) {
- resetDisplay();
+ try {
+ List<CompletionItem> left = eitherCompletableFuture.get().getLeft();
+ AttributedStyle typeStyle = AttributedStyle.DEFAULT.foreground(AttributedStyle.MAGENTA + AttributedStyle.BRIGHT);
+ for (CompletionItem item : left) {
+ List<AttributedString> docs = new ArrayList<>();
+ String type = item.getDetail();
+ if (!Strings.isEmpty(type)) {
+ docs.add(new AttributedString(type, typeStyle));
+ docs.add(new AttributedString(""));
+ }
+ Either<String, MarkupContent> docMap = item.getDocumentation();
+ if (docMap != null) {
+ String doc = docMap.getLeft();
+ if (!Strings.isEmpty(doc)) {
+ docs.add(new AttributedString(doc));
+ }
+ }
+ suggestions.put(new AttributedString(item.getLabel()), docs);
+ }
+ } catch (Exception e) {
+ // ignore
+ // TODO: show exception message in help
}
+ return suggestions;
}
- private void insertHelp() {
- String fileName = buffer.file;
+ @Override
+ protected void insertHelp(int selected) {
+ String fileName = buffer.getFile();
StringBuilder text = new StringBuilder();
- for (String line : this.buffer.lines) {
+ for (String line : this.buffer.getLines()) {
text.append(line);
text.append('\n');
}
// TODO store completions so we don't recompute them when inserting
TextDocumentItem textDocumentItem = new TextDocumentItem(fileName, CamelLanguageServer.LANGUAGE_ID, 0, text.toString());
CompletableFuture<Either<List<CompletionItem>, CompletionList>> eitherCompletableFuture = this.camelDocumentService
- .completionLocal(textDocumentItem, new Position(buffer.line, buffer.offsetInLine + buffer.column));
+ .completionLocal(textDocumentItem,
+ new Position(buffer.getLine(), buffer.getOffsetInLine() + buffer.getColumn()));
List<CompletionItem> lines;
try {
lines = eitherCompletableFuture.get().getLeft();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
- CompletionItem item = lines.get(this.suggestionBox.getSelected());
+ CompletionItem item = lines.get(selected);
Either<TextEdit, InsertReplaceEdit> textEdit = item.getTextEdit();
if (textEdit != null) {
TextEdit left = textEdit.getLeft();
@@ -3199,606 +145,48 @@ public class CamelNanoLspEditor implements Editor {
int startLine = end.getLine();
if (startLine == endLine) {
StringBuilder newLine = new StringBuilder();
- String line = this.buffer.lines.get(startLine);
+ String line = this.buffer.getLines().get(startLine);
newLine.append(line, 0, start.getCharacter());
newLine.append(left.getNewText());
newLine.append(line.substring(end.getCharacter()));
- this.buffer.lines.set(startLine, newLine.toString());
+ this.buffer.getLines().set(startLine, newLine.toString());
this.buffer.moveRight(left.getNewText().length());
} else {
// first line
StringBuilder newFirstLine = new StringBuilder();
- String oldFirstLine = this.buffer.lines.get(startLine);
+ String oldFirstLine = this.buffer.getLines().get(startLine);
String newText = left.getNewText();
newFirstLine.append(oldFirstLine, 0, start.getCharacter());
newFirstLine.append(newText, 0, oldFirstLine.length() - start.getCharacter());
- this.buffer.lines.set(startLine, newFirstLine.toString());
+ this.buffer.getLines().set(startLine, newFirstLine.toString());
// second line
StringBuilder newSecondLine = new StringBuilder();
- String oldSecondLine = this.buffer.lines.get(endLine);
+ String oldSecondLine = this.buffer.getLines().get(endLine);
newSecondLine.append(newText, oldFirstLine.length() - start.getCharacter(), end.getCharacter());
newSecondLine.append(oldSecondLine, end.getCharacter(), end.getCharacter());
- this.buffer.lines.set(endLine, newSecondLine.toString());
+ this.buffer.getLines().set(endLine, newSecondLine.toString());
this.buffer.moveRight(left.getNewText().length());
}
} else if (!Strings.isEmpty(item.getInsertText()) || !Strings.isEmpty(item.getLabel())) {
String insert = Strings.isEmpty(item.getInsertText()) ? item.getLabel() : item.getInsertText();
StringBuilder newLine = new StringBuilder();
- String line = this.buffer.lines.get(buffer.line);
- newLine.append(line, 0, buffer.offsetInLine + buffer.column);
+ String line = this.buffer.getLines().get(buffer.getLine());
+ newLine.append(line, 0, buffer.getOffsetInLine() + buffer.getColumn());
newLine.append(insert);
- this.buffer.lines.set(buffer.line, newLine.toString());
+ this.buffer.getLines().set(buffer.getLine(), newLine.toString());
this.buffer.moveRight(insert.length());
}
- this.buffer.dirty = true;
- }
-
- private void showCompletion(List<AttributedString> newLines) {
- if (this.documentation == null || this.suggestions == null) {
- initDocLines();
- }
- if (suggestions.isEmpty()) {
- resetSuggestion();
- return;
- }
- initBoxes(newLines);
- }
-
- private void initDocLines() {
- this.suggestions = new ArrayList<>();
- this.documentation = new ArrayList<>();
- String fileName = buffer.file;
- StringBuilder text = new StringBuilder();
- for (String line : this.buffer.lines) {
- text.append(line);
- text.append('\n');
- }
- TextDocumentItem textDocumentItem = new TextDocumentItem(fileName, CamelLanguageServer.LANGUAGE_ID, 0, text.toString());
- CompletableFuture<Either<List<CompletionItem>, CompletionList>> eitherCompletableFuture = this.camelDocumentService
- .completionLocal(textDocumentItem, new Position(buffer.line, buffer.offsetInLine + buffer.column));
- if (eitherCompletableFuture.isCompletedExceptionally()) {
- return;
- }
- try {
- List<CompletionItem> left = eitherCompletableFuture.get().getLeft();
- AttributedStyle typeStyle = AttributedStyle.DEFAULT.foreground(AttributedStyle.MAGENTA + AttributedStyle.BRIGHT);
- for (CompletionItem item : left) {
- List<AttributedString> docs = new ArrayList<>();
- String type = item.getDetail();
- if (!Strings.isEmpty(type)) {
- docs.add(new AttributedString(type, typeStyle));
- docs.add(new AttributedString(""));
- }
- Either<String, MarkupContent> docMap = item.getDocumentation();
- if (docMap != null) {
- String doc = docMap.getLeft();
- if (!Strings.isEmpty(doc)) {
- docs.add(new AttributedString(doc));
- }
- }
- if (!docs.isEmpty()) {
- documentation.add(docs);
- }
- suggestions.add(new AttributedString(item.getLabel()));
- }
- } catch (Exception e) {
- // ignore
- // TODO: show exception message in help
- }
- }
-
- private void initBoxes(List<AttributedString> screenLines) {
- // TODO: when there is no space on the right, build boxes to the left of current pos
- // TODO: when there is no space on the bottom, build boxes to the top of current pos
- if (suggestionBox == null) {
- suggestionBox = buildSuggestionBox(suggestions, screenLines);
- }
- addBoxBorders(screenLines, suggestionBox);
- addBoxLines(suggestionBox, screenLines);
- if (!documentation.isEmpty()) {
- Box documentationBox = buildDocumentationBox(screenLines, suggestionBox);
- addBoxBorders(screenLines, documentationBox);
- addBoxLines(documentationBox, screenLines);
- }
- }
-
- private Box buildSuggestionBox(List<AttributedString> suggestions, List<AttributedString> screenLines) {
- // calculate width
- int dXi = buffer.column - 3;
- int xi = Math.max(printLineNumbers ? 9 : 1, dXi);
- int maxSuggestionLength = suggestions.stream().mapToInt(AttributedString::length).max().getAsInt() + 2;
- int screenWidth = (int) Math.round((size.getColumns() - xi) * 0.60); // let's do 60% of what's left of the screen
- int xl = Math.min(maxSuggestionLength + xi, xi + screenWidth);
-
- // calculate height
- int maxHeight = screenLines.size() - 1;
- int yi = buffer.line + 1;
-
- // build suggestion box
- int yl = Math.min(maxHeight, yi + suggestions.size() + 1);
- Box box = new Box(xi, yi, xl, yl);
- box.setLines(suggestions);
- box.setSelectedStyle(AttributedStyle.DEFAULT.background(AttributedStyle.BLUE));
- return box;
- }
-
- private Box buildDocumentationBox(List<AttributedString> screenLines, Box suggestionBox) {
- List<AttributedString> documentation = this.documentation.get(suggestionBox.getSelected());
- //calculate width
- int dXi = suggestionBox.xl;
- int dBoxSize = documentation.stream().mapToInt(AttributedString::length).max().getAsInt() + 2;
- int xi = Math.max(printLineNumbers ? 9 : 1, dXi);
- int maxWidth = (int) Math.round((size.getColumns() - xi) * 0.60); // let's do 60% of what's left of the screen
- int xl = Math.min(dBoxSize + xi, xi + maxWidth);
- //adjust content
- documentation = adjustLines(documentation, dBoxSize - 2, xl - xi - 2);
- // calculate height
- int height = screenLines.size();
- int yi = suggestionBox.yi + suggestionBox.getSelectedInView();
- int yl = yi + documentation.size() + 1;
- if (yl > height - 1) {
- yl = Math.min(height - 1, yi + 2);
- yi = Math.max(1, yl - documentation.size() - 1);
- }
- //create documentation box
- Box documentationBox = new Box(xi, yi, xl, yl);
- documentationBox.setLines(documentation);
- documentationBox.setSelectedStyle(AttributedStyle.DEFAULT);
- return documentationBox;
- }
-
- private void addBoxLines(Box box, List<AttributedString> screenLines) {
- for (int i = 0; i < box.visibleLines.size(); i++) {
- AttributedStringBuilder line = new AttributedStringBuilder(box.xl - box.xi - 2);
- AttributedStyle background = AttributedStyle.DEFAULT;
- if (i == box.getSelectedInView()) {
- background = box.getSelectedStyle();
- }
- line.append(box.visibleLines.get(i), background);
- line.style(background);
- line.append(' ', box.xl - box.xi - line.length() - 2);
- setLineInBox(screenLines, box, box.yi + 1 + i, line.toAttributedString(), false);
- }
- }
-
- private List<AttributedString> adjustLines(List<AttributedString> lines, int max, int boxLength) {
- if (max <= boxLength) {
- return lines;
- }
- List<AttributedString> adjustedLines = new ArrayList<>();
- for (AttributedString line : lines) {
- if (line.length() < boxLength) {
- adjustedLines.add(line);
- } else {
- int start = 0;
- while (start < line.length()) {
- int stepSize = Math.min(start + boxLength, line.length());
- int end = stepSize;
- // check last line
- if (end - start >= boxLength) {
- // let's not cutoff in the middle of a word.
- while (end > start && !Character.isWhitespace(line.charAt(end - 1))) {
- end--;
- }
- }
- if (end == start) {
- // there was no space, let's not loop forever
- end = stepSize;
- }
- adjustedLines.add(line.substring(start, end));
- start = end;
- }
- }
- }
- return adjustedLines;
- }
-
- private void addBoxBorders(List<AttributedString> newLines, Box box) {
- int width = box.xl - box.xi;
- AttributedStringBuilder top = new AttributedStringBuilder(width);
- top.append('┌');
- top.append('─', width - 2);
- top.append('┐');
- setLineInBox(newLines, box, box.yi, top.toAttributedString(), true);
- AttributedStringBuilder sides = new AttributedStringBuilder(width);
- sides.append('│');
- sides.append(' ', width - 2);
- sides.append('│');
- AttributedString side = sides.toAttributedString();
- for (int y = box.yi + 1; y < box.yl; y++) {
- setLineInBox(newLines, box, y, side, true);
- }
- AttributedStringBuilder bottom = new AttributedStringBuilder(width);
- bottom.append('└');
- bottom.append('─', width - 2);
- bottom.append('┘');
- setLineInBox(newLines, box, box.yl, bottom.toAttributedString(), true);
- }
-
- private void setLineInBox(List<AttributedString> newLines, Box box, int y, AttributedString line, boolean borders) {
- int start = box.xi;
- int end = box.xl;
- if (!borders) {
- start++;
- end--;
- }
- AttributedString currLine = newLines.get(y);
- AttributedStringBuilder newLine = new AttributedStringBuilder(Math.max(end, currLine.length()) + 1);
- int currLength = currLine.length();
- // add carriage return at the end of the line
- if (currLine.charAt(currLength - 1) == '\n') {
- currLength -= 1;
- }
- newLine.append(currLine, 0, Math.min(start, currLength));
- newLine.append(' ', start - currLength);
- newLine.append(line);
- newLine.append(currLine, start + line.length(), currLength);
- if (currLength == currLine.length() - 1) {
- newLine.append('\n');
- }
- newLines.set(y, newLine.toAttributedString());
- }
-
- protected List<AttributedString> computeFooter() {
- List<AttributedString> footer = new ArrayList<>();
-
- if (editMessage != null) {
- AttributedStringBuilder sb = new AttributedStringBuilder();
- sb.style(AttributedStyle.INVERSE);
- sb.append(editMessage);
- sb.append(editBuffer);
- for (int i = editMessage.length() + editBuffer.length(); i < size.getColumns(); i++) {
- sb.append(' ');
- }
- sb.append('\n');
- footer.add(sb.toAttributedString());
- } else if (message != null || constantCursor) {
- int rwidth = size.getColumns();
- String text = "[ " + (message == null ? computeCurPos() : message) + " ]";
- int len = text.length();
- AttributedStringBuilder sb = new AttributedStringBuilder();
- for (int i = 0; i < (rwidth - len) / 2; i++) {
- sb.append(' ');
- }
- sb.style(AttributedStyle.INVERSE);
- sb.append(text);
- sb.append('\n');
- footer.add(sb.toAttributedString());
- } else {
- footer.add(new AttributedString("\n"));
- }
-
- Iterator<Entry<String, String>> sit = shortcuts.entrySet().iterator();
- int cols = (shortcuts.size() + 1) / 2;
- int cw = (size.getColumns() - 1) / cols;
- int rem = (size.getColumns() - 1) % cols;
- for (int l = 0; l < 2; l++) {
- AttributedStringBuilder sb = new AttributedStringBuilder();
- for (int c = 0; c < cols; c++) {
- Entry<String, String> entry = sit.hasNext() ? sit.next() : null;
- String key = entry != null ? entry.getKey() : "";
- String val = entry != null ? entry.getValue() : "";
- sb.style(AttributedStyle.INVERSE);
- sb.append(key);
- sb.style(AttributedStyle.DEFAULT);
- sb.append(" ");
- int nb = cw - key.length() - 1 + (c < rem ? 1 : 0);
- if (val.length() > nb) {
- sb.append(val.substring(0, nb));
- } else {
- sb.append(val);
- if (c < cols - 1) {
- for (int i = 0; i < nb - val.length(); i++) {
- sb.append(" ");
- }
- }
- }
- }
- sb.append('\n');
- footer.add(sb.toAttributedString());
- }
-
- return footer;
- }
-
- protected void handle(Signal signal) {
- if (buffer != null) {
- size.copy(terminal.getSize());
- buffer.computeAllOffsets();
- buffer.moveToChar(buffer.offsetInLine + buffer.column);
- resetDisplay();
- display();
- }
- }
-
- protected void bindKeys() {
- keys = new KeyMap<>();
- if (!view) {
- keys.setUnicode(Operation.INSERT);
-
- for (char i = 32; i < KEYMAP_LENGTH; i++) {
- keys.bind(Operation.INSERT, Character.toString(i));
- }
- keys.bind(Operation.BACKSPACE, del());
- for (char i = 'A'; i <= 'Z'; i++) {
- keys.bind(Operation.DO_LOWER_CASE, alt(i));
- }
- keys.bind(Operation.WRITE, ctrl('O'), key(terminal, Capability.key_f3));
- keys.bind(Operation.JUSTIFY_PARAGRAPH, ctrl('J'), key(terminal, Capability.key_f4));
- keys.bind(Operation.CUT, ctrl('K'), key(terminal, Capability.key_f9));
- keys.bind(Operation.UNCUT, ctrl('U'), key(terminal, Capability.key_f10));
- keys.bind(Operation.REPLACE, ctrl('\\'), key(terminal, Capability.key_f14), alt('r'));
- keys.bind(Operation.MARK, ctrl('^'), key(terminal, Capability.key_f15), alt('a'));
- keys.bind(Operation.COPY, alt('^'), alt('6'));
- keys.bind(Operation.INDENT, alt('}'));
- keys.bind(Operation.UNINDENT, alt('{'));
- keys.bind(Operation.VERBATIM, alt('v'));
- keys.bind(Operation.INSERT, ctrl('I'), ctrl('M'));
- keys.bind(Operation.DELETE, ctrl('D'), key(terminal, Capability.key_dc));
- keys.bind(Operation.BACKSPACE, ctrl('H'));
- keys.bind(Operation.CUT_TO_END, alt('t'));
- keys.bind(Operation.JUSTIFY_FILE, alt('j'));
- keys.bind(Operation.AUTO_INDENT, alt('i'));
- keys.bind(Operation.CUT_TO_END_TOGGLE, alt('k'));
- keys.bind(Operation.TABS_TO_SPACE, alt('q'));
- } else {
- keys.bind(Operation.NEXT_PAGE, " ", "f");
- keys.bind(Operation.PREV_PAGE, "b");
- }
- keys.bind(Operation.NEXT_PAGE, ctrl('V'), key(terminal, Capability.key_f8));
- keys.bind(Operation.PREV_PAGE, ctrl('Y'), key(terminal, Capability.key_f7));
-
- keys.bind(Operation.HELP, ctrl('G'), key(terminal, Capability.key_f1));
- keys.bind(Operation.QUIT, ctrl('X'), key(terminal, Capability.key_f2));
-
- keys.bind(Operation.READ, ctrl('R'), key(terminal, Capability.key_f5));
- keys.bind(Operation.SEARCH, ctrl('W'), key(terminal, Capability.key_f6));
-
- keys.bind(Operation.CUR_POS, ctrl('C'), key(terminal, Capability.key_f11));
- keys.bind(Operation.TO_SPELL, ctrl('T'), key(terminal, Capability.key_f11));
-
- keys.bind(Operation.GOTO, ctrl('_'), key(terminal, Capability.key_f13), alt('g'));
- keys.bind(Operation.NEXT_SEARCH, key(terminal, Capability.key_f16), alt('w'));
-
- keys.bind(Operation.RIGHT, ctrl('F'));
- keys.bind(Operation.LEFT, ctrl('B'));
- keys.bind(Operation.LSP_SUGGESTION, ctrl(' '));
- keys.bind(Operation.UP, ctrl('P'));
- keys.bind(Operation.DOWN, ctrl('N'));
-
- keys.bind(Operation.BEGINNING_OF_LINE, ctrl('A'), key(terminal, Capability.key_home));
- keys.bind(Operation.END_OF_LINE, ctrl('E'), key(terminal, Capability.key_end));
- keys.bind(Operation.BEGINNING_OF_PARAGRAPH, alt('('), alt('9'));
- keys.bind(Operation.END_OF_PARAGRAPH, alt(')'), alt('0'));
- keys.bind(Operation.FIRST_LINE, alt('\\'), alt('|'));
- keys.bind(Operation.LAST_LINE, alt('/'), alt('?'));
-
- keys.bind(Operation.MATCHING, alt(']'));
- keys.bind(Operation.SCROLL_UP, alt('-'), alt('_'));
- keys.bind(Operation.SCROLL_DOWN, alt('+'), alt('='));
-
- keys.bind(Operation.PREV_BUFFER, alt('<'));
- keys.bind(Operation.NEXT_BUFFER, alt('>'));
- keys.bind(Operation.PREV_BUFFER, alt(','));
- keys.bind(Operation.NEXT_BUFFER, alt('.'));
-
- keys.bind(Operation.COUNT, alt('d'));
- keys.bind(Operation.CLEAR_SCREEN, ctrl('L'));
-
- keys.bind(Operation.HELP, alt('x'));
- keys.bind(Operation.CONSTANT_CURSOR, alt('c'));
- keys.bind(Operation.ONE_MORE_LINE, alt('o'));
- keys.bind(Operation.SMOOTH_SCROLLING, alt('s'));
- keys.bind(Operation.MOUSE_SUPPORT, alt('m'));
- keys.bind(Operation.WHITESPACE, alt('p'));
- keys.bind(Operation.HIGHLIGHT, alt('y'));
-
- keys.bind(Operation.SMART_HOME_KEY, alt('h'));
- keys.bind(Operation.WRAP, alt('l'));
-
- keys.bind(Operation.BACKUP, alt('b'));
- keys.bind(Operation.NUMBERS, alt('n'));
-
- keys.bind(Operation.UP, key(terminal, Capability.key_up));
- keys.bind(Operation.DOWN, key(terminal, Capability.key_down));
- keys.bind(Operation.RIGHT, key(terminal, Capability.key_right));
- keys.bind(Operation.LEFT, key(terminal, Capability.key_left));
- keys.bind(Operation.MOUSE_EVENT, key(terminal, Capability.key_mouse));
- keys.bind(Operation.TOGGLE_SUSPENSION, alt('z'));
- keys.bind(Operation.NEXT_PAGE, key(terminal, Capability.key_npage));
- keys.bind(Operation.PREV_PAGE, key(terminal, Capability.key_ppage));
- }
-
- protected enum Operation {
- DO_LOWER_CASE,
-
- QUIT,
- WRITE,
- READ,
- GOTO,
- FIND,
-
- WRAP,
- NUMBERS,
- SMOOTH_SCROLLING,
- MOUSE_SUPPORT,
- ONE_MORE_LINE,
- CLEAR_SCREEN,
-
- UP,
- DOWN,
- LEFT,
- RIGHT,
-
- INSERT,
- BACKSPACE,
-
- NEXT_BUFFER,
- PREV_BUFFER,
-
- HELP,
- NEXT_PAGE,
- PREV_PAGE,
- SCROLL_UP,
- SCROLL_DOWN,
- LSP_SUGGESTION,
- BEGINNING_OF_LINE,
- END_OF_LINE,
- FIRST_LINE,
- LAST_LINE,
-
- CUR_POS,
-
- CASE_SENSITIVE,
- BACKWARDS,
- REGEXP,
- ACCEPT,
- CANCEL,
- SEARCH,
- TOGGLE_REPLACE,
- MAC_FORMAT,
- DOS_FORMAT,
- APPEND_MODE,
- PREPEND_MODE,
- BACKUP,
- TO_FILES,
- YES,
- NO,
- ALL,
- NEW_BUFFER,
- EXECUTE,
- NEXT_SEARCH,
- MATCHING,
- VERBATIM,
- DELETE,
-
- JUSTIFY_PARAGRAPH,
- TO_SPELL,
- CUT,
- REPLACE,
- MARK,
- COPY,
- INDENT,
- UNINDENT,
- BEGINNING_OF_PARAGRAPH,
- END_OF_PARAGRAPH,
- CUT_TO_END,
- JUSTIFY_FILE,
- COUNT,
- CONSTANT_CURSOR,
- WHITESPACE,
- HIGHLIGHT,
- SMART_HOME_KEY,
- AUTO_INDENT,
- CUT_TO_END_TOGGLE,
- TABS_TO_SPACE,
- UNCUT,
-
- MOUSE_EVENT,
-
- TOGGLE_SUSPENSION
- }
-
- //y axis (xi,yi)┌──────────────────────────────┐(xl,yi)
- // │ │
- // │ │
- // │ │
- // │ │
- // │ │
- // │ │
- // │ │
- // (xi,yl)└──────────────────────────────┘(xl,yl)
- // x axis
- private static class Box {
- // (xi,yi) upper left
- // (xl,yi) upper right
- // (xi,yl) lower left
- // (xl,yl) lower right
- private final int xi, xl, yi, yl;
- private List<AttributedString> lines;
- private int selected = 0;
- private int selectedInView = 0;
- private final int size;
- private AttributedStyle selectedStyle = AttributedStyle.DEFAULT;
- private List<AttributedString> visibleLines;
-
- private Box(int xi, int yi, int xl, int yl) {
- this.xi = xi;
- this.yi = yi;
- this.xl = xl;
- this.yl = yl;
- this.size = yl - yi - 1;
- }
-
- private void setLines(List<AttributedString> lines) {
- this.lines = lines;
- this.visibleLines = lines.subList(0, size);
- }
-
- private int getSelected() {
- return selected;
- }
-
- private void setSelectedStyle(AttributedStyle selectedStyle) {
- this.selectedStyle = selectedStyle;
- }
-
- private AttributedStyle getSelectedStyle() {
- return selectedStyle;
- }
-
- private void down() {
- selected = Math.floorMod(selected + 1, lines.size());
- if (!scrollable() || selectedInView < size - 1) {
- selectedInView++;
- return;
- }
- // calculate new view
- if (selected == 0) {
- // return to the beginning of list
- selectedInView = 0;
- visibleLines = lines.subList(0, size);
- } else {
- visibleLines = lines.subList(selected - size + 1, selected + 1);
- }
- }
-
- private void up() {
- selected = Math.floorMod(selected - 1, lines.size());
- if (!scrollable() || selectedInView > 0) {
- selectedInView--;
- return;
- }
- // calculate new view
- if (selected == lines.size() - 1) {
- // last element in list, return to beginning
- this.selectedInView = this.size - 1;
- this.visibleLines = this.lines.subList(this.lines.size() - size, this.lines.size());
- } else {
- this.visibleLines = this.lines.subList(selected, selected + size);
- }
- }
-
- private boolean scrollable() {
- return this.size < this.lines.size();
- }
-
- private int getSelectedInView() {
- return Math.floorMod(selectedInView, lines.size());
- }
+ this.buffer.setDirty(true);
}
private static class LocalCamelDocumentService extends CamelTextDocumentService {
- private EndpointDiagnosticService endpointDiagnosticService;
- private ConfigurationPropertiesDiagnosticService configurationPropertiesDiagnosticService;
- private CamelKModelineDiagnosticService camelKModelineDiagnosticService;
- private ConnectedModeDiagnosticService connectedModeDiagnosticService;
+ private final EndpointDiagnosticService endpointDiagnosticService;
+ private final ConfigurationPropertiesDiagnosticService configurationPropertiesDiagnosticService;
+ private final CamelKModelineDiagnosticService camelKModelineDiagnosticService;
+ private final ConnectedModeDiagnosticService connectedModeDiagnosticService;
private LocalCamelDocumentService() {
super(null);
- }
-
- private void init() {
endpointDiagnosticService = new EndpointDiagnosticService(getCamelCatalog());
configurationPropertiesDiagnosticService = new ConfigurationPropertiesDiagnosticService(getCamelCatalog());
camelKModelineDiagnosticService = new CamelKModelineDiagnosticService();
@@ -3822,7 +210,7 @@ public class CamelNanoLspEditor implements Editor {
String camelText = documentItem.getText();
Map<CamelEndpointDetails, EndpointValidationResult> endpointErrors
= endpointDiagnosticService.computeCamelEndpointErrors(camelText, uri);
- List<Diagnostic> diagnostics
+ List<org.eclipse.lsp4j.Diagnostic> diagnostics
= endpointDiagnosticService.converToLSPDiagnostics(camelText, endpointErrors, documentItem);
Map<String, ConfigurationPropertiesValidationResult> configurationPropertiesErrors
= configurationPropertiesDiagnosticService.computeCamelConfigurationPropertiesErrors(camelText, uri);
@@ -3830,7 +218,42 @@ public class CamelNanoLspEditor implements Editor {
diagnostics.addAll(camelKModelineDiagnosticService.compute(camelText, documentItem));
diagnostics.addAll(connectedModeDiagnosticService.compute(camelText, documentItem));
diagnostics.addAll(connectedModeDiagnosticService.compute(camelText, documentItem));
- return diagnostics;
+ return diagnostics.stream()
+ .map(diag -> (Diagnostic) new DiagnosticWrapper(diag))
+ .toList();
+ }
+
+ private static class DiagnosticWrapper implements Diagnostic {
+ private final org.eclipse.lsp4j.Diagnostic diag;
+
+ public DiagnosticWrapper(org.eclipse.lsp4j.Diagnostic diag) {
+ this.diag = diag;
+ }
+
+ @Override
+ public int getStartLine() {
+ return diag.getRange().getStart().getLine();
+ }
+
+ @Override
+ public int getStartColumn() {
+ return diag.getRange().getStart().getCharacter();
+ }
+
+ @Override
+ public int getEndLine() {
+ return diag.getRange().getEnd().getLine();
+ }
+
+ @Override
+ public int getEndColumn() {
+ return diag.getRange().getEnd().getCharacter();
+ }
+
+ @Override
+ public String getMessage() {
+ return diag.getMessage();
+ }
}
}
}
diff --git a/parent/pom.xml b/parent/pom.xml
index a2b5cfef771..2c996050d8e 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -294,7 +294,7 @@
<jgroups-raft-leveldbjni-version>1.8</jgroups-raft-leveldbjni-version>
<jgroups-raft-mapdb-version>1.0.8</jgroups-raft-mapdb-version>
<jira-rest-client-api-version>6.0.2</jira-rest-client-api-version>
- <jline-version>3.29.0</jline-version>
+ <jline-version>3.30.0</jline-version>
<libthrift-version>0.21.0</libthrift-version>
<jodatime2-version>2.14.0</jodatime2-version>
<jolokia-version>2.2.9</jolokia-version>