Skip to content

Commit

Permalink
Nano config file: support 'set/unset <option>'
Browse files Browse the repository at this point in the history
  • Loading branch information
mattirn committed Sep 13, 2019
1 parent 470206b commit f987907
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 72 deletions.
8 changes: 3 additions & 5 deletions builtins/src/main/java/org/jline/builtins/Commands.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
*/
package org.jline.builtins;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -20,7 +18,6 @@
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
Expand Down Expand Up @@ -115,7 +112,8 @@ public static void nano(Terminal terminal, PrintStream out, PrintStream err,
" -? --help Show help",
" -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."
" and don't use backup files.",
" -Y --syntax=name The name of the syntax highlighting to use."
};
Options opt = Options.compile(usage).parse(argv);
if (opt.isSet("help")) {
Expand Down Expand Up @@ -253,7 +251,7 @@ public static void history(LineReader reader, PrintStream out, PrintStream err,
}
ReExecute execute = new ReExecute(history, opt);
int argId = execute.getArgId();

Pattern pattern = null;
if (opt.isSet("m") && opt.args().size() > argId) {
StringBuilder sb = new StringBuilder();
Expand Down
179 changes: 114 additions & 65 deletions builtins/src/main/java/org/jline/builtins/Nano.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,14 @@ public class Nano implements Editor {
public boolean mouseSupport = false;
public boolean oneMoreLine = true;
public boolean constantCursor;
public boolean quickblank = false;
public int tabs = 1; // tabs are not currently supported!
public String brackets = "\"’)>]}";
public String matchBrackets = "(<[{)>]}";
public String punct = "!.?";
public String quoteStr = "^([ \\t]*[#:>\\|}])+";
private boolean restricted;
private String syntaxName;
private List<Path> syntaxFiles = new ArrayList<>();

// Input
Expand All @@ -111,7 +114,6 @@ public class Nano implements Editor {
protected boolean searchCaseSensitive;
protected boolean searchRegexp;
protected boolean searchBackwards;
protected boolean restricted;
protected String searchTerm;
protected List<String> searchTerms = new ArrayList<>();
protected int searchTermId = -1;
Expand All @@ -120,6 +122,7 @@ public class Nano implements Editor {
protected List<String> cutbuffer = new ArrayList<>();
protected boolean cut2end = false;
protected boolean mark = false;
protected boolean highlight = true;

protected boolean readNewBuffer = true;
protected String errorMessage = null;
Expand Down Expand Up @@ -671,7 +674,8 @@ List<AttributedString> computeHeader() {
}

void highlightDisplayedLine(int curLine, int curOffset, int nextOffset, AttributedStringBuilder line){
AttributedString disp = syntaxHighlighter.highlightNextLine(new AttributedString(getLine(curLine)));
AttributedString disp = highlight ? syntaxHighlighter.highlightNextLine(new AttributedString(getLine(curLine)))
: new AttributedString(getLine(curLine));
if (!mark) {
line.append(disp.columnSubSequence(curOffset, nextOffset));
} else if (getMarkStart()[0] == getMarkEnd()[0]) {
Expand Down Expand Up @@ -728,18 +732,22 @@ void highlightDisplayedLine(int curLine, int curOffset, int nextOffset, Attribut

private SyntaxHighlighter doSyntaxHighlighter() {
SyntaxHighlighter out = new SyntaxHighlighter();
if (file != null) {
List<HighlightRule> defaultRules = new ArrayList<>();
if (file != null && (syntaxName == null || (syntaxName != null && !syntaxName.equals("none")))) {
for (Path p: syntaxFiles) {
NanorcParser parser = new NanorcParser(p, file);
NanorcParser parser = new NanorcParser(p, syntaxName, file);
try {
parser.parse();
if (parser.matches()) {
out.addRules(parser.getHighlightRules());
return out;
} else if (parser.isDefault()) {
defaultRules.addAll(parser.getHighlightRules());
}
} catch (IOException e) {
}
}
out.addRules(defaultRules);
}
return out;
}
Expand Down Expand Up @@ -1387,57 +1395,18 @@ public static RuleType evalRuleType(List<String> colorCfg){

}

private static class ConfigParser extends Parser {
private File file;
private String message;
private List<Path> syntaxFiles = new ArrayList<>();

public ConfigParser(Path file) {
this.file = file.toFile();
}

public void parse() throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = reader.readLine();
while (line!= null) {
line = line.trim();
if (line.length() > 0 && !line.startsWith("#")) {
List<String> parts = split(line);
if (parts.get(0).equals("include")) {
if (parts.get(1).contains("*") || parts.get(1).contains("?")) {
PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + parts.get(1));
Files.find(Paths.get(new File(parts.get(1)).getParent()), Integer.MAX_VALUE, (path, f) -> pathMatcher.matches(path))
.forEach(p -> syntaxFiles.add(p));
} else {
syntaxFiles.add(Paths.get(parts.get(1)));
}
} else {
message = "Nano config: Only 'include' entries are supported!";
}
}
line = reader.readLine();
}
reader.close();
}

public String getMessage() {
return message;
}

public List<Path> getSyntaxFiles() {
return syntaxFiles;
}

}

private static class NanorcParser extends Parser {
private static class NanorcParser {
private static final String DEFAULT_SYNTAX = "default";
private File file;
private String name;
private String target;
private boolean matches = false;
private List<HighlightRule> highlightRules = new ArrayList<>();
private String syntaxName;

public NanorcParser(Path file, String target) {
public NanorcParser(Path file, String name, String target) {
this.file = file.toFile();
this.name = name;
this.target = target;
}

Expand All @@ -1448,20 +1417,27 @@ public void parse() throws IOException {
line = line.trim();
if (line.length() > 0 && !line.startsWith("#")) {
line = line.replaceAll("\\\\<", "\\\\b").replaceAll("\\\\>", "\\\\b").replaceAll("\\[\\[:space:\\]\\]", "\\\\s");
List<String> parts = split(line);
List<String> parts = Parser.split(line);
if (parts.get(0).equals("syntax")) {
syntaxName = parts.get(1);
List<Pattern> filePatterns = new ArrayList<>();
for (int i = 2; i < parts.size(); i++) {
filePatterns.add(Pattern.compile(parts.get(i)));
}
if (target != null) {
if (name != null) {
if (name.equals(syntaxName)) {
matches = true;
} else {
break;
}
} else if (target != null) {
for (int i = 2; i < parts.size(); i++) {
filePatterns.add(Pattern.compile(parts.get(i)));
}
for (Pattern p: filePatterns) {
if (p.matcher(target).find()) {
matches = true;
break;
}
}
if (!matches) {
if (!matches && !syntaxName.equals(DEFAULT_SYNTAX)) {
break;
}
} else {
Expand All @@ -1486,6 +1462,10 @@ public List<HighlightRule> getHighlightRules() {
return highlightRules;
}

public boolean isDefault() {
return syntaxName.equals(DEFAULT_SYNTAX);
}

private Integer toColor(String styleString) {
Integer out = null;
if (styleString.length() > 0) {
Expand Down Expand Up @@ -1547,8 +1527,8 @@ private Pattern doPattern(String regex, boolean caseInsensitive) {

}

private static abstract class Parser {
protected List<String> split(String s){
private static class Parser {
protected static List<String> split(String s){
List<String> out = new ArrayList<String>();
if (s.length() == 0) {
return out;
Expand All @@ -1574,7 +1554,7 @@ protected List<String> split(String s){
return out;
}

private String stripQuotes(String s){
private static String stripQuotes(String s){
String out = s.trim();
if (s.startsWith("\"") && s.endsWith("\"")) {
out = s.substring(1, s.length() - 1);
Expand All @@ -1601,15 +1581,11 @@ public Nano(Terminal terminal, Path root, Options opts, Path nanorc) {
this.display = new Display(terminal, true);
this.bindingReader = new BindingReader(terminal.reader());
this.size = new Size();
this.restricted = opts != null && opts.isSet("restricted");
this.vsusp = terminal.getAttributes().getControlChar(ControlChar.VSUSP);
bindKeys();
if (nanorc != null && nanorc.toFile().exists()) {
ConfigParser parser = new ConfigParser(nanorc);
try {
parser.parse();
syntaxFiles = parser.getSyntaxFiles();
errorMessage = parser.getMessage();
parseConfig(nanorc);
} catch (IOException e) {
errorMessage = "Encountered error while reading config file: " + nanorc;
}
Expand All @@ -1622,6 +1598,75 @@ public Nano(Terminal terminal, Path root, Options opts, Path nanorc) {
errorMessage = "Encountered error while reading nanorc files";
}
}
if (opts != null) {
this.restricted = opts.isSet("restricted");
this.syntaxName = opts.isSet("syntax") ? opts.get("syntax") : null;
}
}

private void parseConfig(Path file) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(file.toFile()));
String line = reader.readLine();
while (line!= null) {
line = line.trim();
if (line.length() > 0 && !line.startsWith("#")) {
List<String> parts = Parser.split(line);
if (parts.get(0).equals("include")) {
if (parts.get(1).contains("*") || parts.get(1).contains("?")) {
PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + parts.get(1));
Files.find(Paths.get(new File(parts.get(1)).getParent()), Integer.MAX_VALUE, (path, f) -> pathMatcher.matches(path))
.forEach(p -> syntaxFiles.add(p));
} else {
syntaxFiles.add(Paths.get(parts.get(1)));
}
} else if (parts.size() == 2
&& (parts.get(0).equals("set") || parts.get(0).equals("unset"))) {
String option = parts.get(1);
boolean val = parts.get(0).equals("set");
if (option.equals("linenumbers")) {
printLineNumbers = val;
} else if (option.equals("jumpyscrolling")) {
smoothScrolling = !val;
} else if (option.equals("smooth")) {
smoothScrolling = val;
} else if (option.equals("softwrap")) {
wrapping = val;
} else if (option.equals("mouse")) {
mouseSupport = val;
} else if (option.equals("emptyline")) {
oneMoreLine = val;
} else if (option.equals("morespace")) {
oneMoreLine = !val;
} else if (option.equals("constantshow")) {
constantCursor = val;
} else if (option.equals("quickblank")) {
quickblank = val;
} else {
errorMessage = "Nano config: Unknown or unsupported configuration option " + option;
}
} else if (parts.size() == 3 && parts.get(0).equals("set")) {
String option = parts.get(1);
String val = parts.get(2);
if (option.equals("quotestr")) {
quoteStr = val;
} else if (option.equals("punct")) {
punct = val;
} else if (option.equals("matchbrackets")) {
matchBrackets = val;
} else if (option.equals("brackets")) {
brackets = val;
} else {
errorMessage = "Nano config: Unknown or unsupported configuration option " + option;
}
} else if (parts.get(0).equals("bind") || parts.get(0).equals("unbind")) {
errorMessage = "Nano config: Key bindings can not be changed!";
} else {
errorMessage = "Nano config: Bad configuration '" + line + "'";
}
}
line = reader.readLine();
}
reader.close();
}

public void setRestricted(boolean restricted) {
Expand Down Expand Up @@ -1832,6 +1877,10 @@ public void run() throws IOException {
setMessage("Mark " + (mark ? "Set" : "Unset"));
buffer.mark();
break;
case HIGHLIGHT:
highlight = !highlight;
setMessage("Highlight " + (highlight ? "enabled" : "disabled"));
break;
default:
setMessage("Unsupported " + op.name().toLowerCase().replace('_', '-'));
break;
Expand Down Expand Up @@ -2598,8 +2647,8 @@ void nextBuffer() throws IOException {
}

void setMessage(String message) {
this.message = message;
this.nbBindings = 25;
this.message = message;
this.nbBindings = quickblank ? 2 : 25;
}

boolean quit() throws IOException {
Expand Down
4 changes: 2 additions & 2 deletions demo/src/main/java/org/apache/felix/gogo/jline/Posix.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
import org.jline.builtins.Less;
import org.jline.builtins.Nano;
import org.jline.builtins.Options;
import org.jline.builtins.Options.HelpException;
import org.jline.builtins.Source;
import org.jline.builtins.Source.PathSource;
import org.jline.builtins.Source.URLSource;
Expand Down Expand Up @@ -868,7 +867,8 @@ protected void nano(final CommandSession session, Process process, String[] argv
" -? --help Show help",
" -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."
" and don't use backup files.",
" -Y --syntax=name The name of the syntax highlighting to use."
};
Options opt = parseOptions(session, usage, argv);
Nano edit = new Nano(Shell.getTerminal(session), session.currentDir(), opt);
Expand Down

0 comments on commit f987907

Please sign in to comment.