Skip to content

Commit

Permalink
highlighter command: add option --switch=theme
Browse files Browse the repository at this point in the history
  • Loading branch information
mattirn committed Dec 16, 2021
1 parent 7ae2b8b commit 1aae0ae
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 65 deletions.
148 changes: 88 additions & 60 deletions builtins/src/main/java/org/jline/builtins/Commands.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package org.jline.builtins;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.FileSystems;
import java.nio.file.Path;
Expand All @@ -26,6 +27,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

import org.jline.builtins.Completers.CompletionData;
import org.jline.builtins.Options.HelpException;
Expand Down Expand Up @@ -1573,13 +1575,14 @@ public void printColor(String name, String style) throws IOException {
public static void highlighter(LineReader lineReader, Terminal terminal, PrintStream out, PrintStream err, String[] argv,
ConfigurationPath configPath) throws HelpException {
final String[] usage = {
"highlighter - refresh highlighter config and view themes",
"highlighter - manage nanorc theme system",
"Usage: highlighter [OPTIONS]",
" -? --help Displays command help",
" -c --columns=COLUMNS Number of columns in theme view",
" -l --list List available nanorc themes",
" -r --refresh Refresh highlighter config",
" -v --view [THEME] View nanorc theme",
" -s --switch=THEME Switch nanorc theme",
" -v --view=THEME View nanorc theme",
};
Options opt = Options.compile(usage).parse(argv);
if (opt.isSet("help")) {
Expand All @@ -1588,77 +1591,102 @@ public static void highlighter(LineReader lineReader, Terminal terminal, PrintSt
try {
if (opt.isSet("refresh")) {
lineReader.getHighlighter().refresh(lineReader);
}
if (opt.isSet("view")) {
SyntaxHighlighter sh = SyntaxHighlighter.build(configPath.getConfig(DEFAULT_NANORC_FILE), null);
Path currentTheme = sh.getCurrentTheme();
File themeFile;
if (opt.args().isEmpty()) {
themeFile = currentTheme.toFile();
} else {
themeFile = new File(replaceFileName(currentTheme, opt.args().get(0)));
} else if (opt.isSet("switch")) {
Path userConfig = configPath.getUserConfig(DEFAULT_NANORC_FILE);
if (userConfig != null) {
SyntaxHighlighter sh = SyntaxHighlighter.build(userConfig, null);
Path currentTheme = sh.getCurrentTheme();
String newTheme = replaceFileName(currentTheme, opt.get("switch"));
File themeFile = new File(newTheme);
if (themeFile.exists()) {
switchTheme(err, userConfig, newTheme);
Path lessConfig = configPath.getUserConfig(DEFAULT_LESSRC_FILE);
if (lessConfig != null) {
switchTheme(err, lessConfig, newTheme);
}
lineReader.getHighlighter().refresh(lineReader);
}
}
out.println(themeFile.getAbsolutePath());
try (BufferedReader reader = new BufferedReader(new FileReader(themeFile))) {
String line;
List<List<String>> tokens = new ArrayList<>();
int maxKeyLen = 0;
int maxValueLen = 0;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.length() > 0 && !line.startsWith("#")) {
List<String> parts = Arrays.asList(line.split("\\s+", 2));
if (parts.get(0).matches(REGEX_TOKEN_NAME)) {
if (parts.get(0).length() > maxKeyLen) {
maxKeyLen = parts.get(0).length();
} else {
Path config = configPath.getConfig(DEFAULT_NANORC_FILE);
Path currentTheme = config != null ? SyntaxHighlighter.build(config, null).getCurrentTheme() : null;
if (currentTheme != null) {
if (opt.isSet("list")) {
String parameter = replaceFileName(currentTheme, "*" + TYPE_NANORCTHEME);
out.println(currentTheme.getParent() + ":");
PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + parameter);
Files.find(Paths.get(new File(parameter).getParent()), Integer.MAX_VALUE
, (path, f) -> pathMatcher.matches(path))
.forEach(p -> out.println(p.getFileName()));
} else {
File themeFile;
if (opt.isSet("view")) {
themeFile = new File(replaceFileName(currentTheme, opt.get("view")));
} else {
themeFile = currentTheme.toFile();
}
out.println(themeFile.getAbsolutePath());
try (BufferedReader reader = new BufferedReader(new FileReader(themeFile))) {
String line;
List<List<String>> tokens = new ArrayList<>();
int maxKeyLen = 0;
int maxValueLen = 0;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.length() > 0 && !line.startsWith("#")) {
List<String> parts = Arrays.asList(line.split("\\s+", 2));
if (parts.get(0).matches(REGEX_TOKEN_NAME)) {
if (parts.get(0).length() > maxKeyLen) {
maxKeyLen = parts.get(0).length();
}
if (parts.get(1).length() > maxValueLen) {
maxValueLen = parts.get(1).length();
}
tokens.add(parts);
}
}
if (parts.get(1).length() > maxValueLen) {
maxValueLen = parts.get(1).length();
}
AttributedStringBuilder asb = new AttributedStringBuilder();
maxKeyLen = maxKeyLen + 2;
maxValueLen = maxValueLen + 1;
int cols = opt.isSet("columns") ? opt.getNumber("columns") : 2;
List<Integer> tabstops = new ArrayList<>();
for (int c = 0; c < cols; c++) {
tabstops.add((c + 1) * maxKeyLen + c * maxValueLen);
tabstops.add((c + 1) * maxKeyLen + (c + 1) * maxValueLen);
}
asb.tabs(tabstops);
int ind = 0;
for (List<String> token : tokens) {
asb.style(AttributedStyle.DEFAULT).append(" ");
asb.style(compileStyle("token" + ind++, token.get(1)));
asb.append(token.get(0)).append("\t");
asb.append(token.get(1));
asb.style(AttributedStyle.DEFAULT).append("\t");
if ((ind % cols) == 0) {
asb.style(AttributedStyle.DEFAULT).append("\n");
}
tokens.add(parts);
}
asb.toAttributedString().println(terminal);
}
}
AttributedStringBuilder asb = new AttributedStringBuilder();
maxKeyLen = maxKeyLen + 2;
maxValueLen = maxValueLen + 1;
int cols = opt.isSet("columns") ? opt.getNumber("columns") : 2;
List<Integer> tabstops = new ArrayList<>();
for (int c = 0; c < cols; c++) {
tabstops.add((c + 1)*maxKeyLen + c*maxValueLen);
tabstops.add((c + 1)*maxKeyLen + (c + 1)*maxValueLen);
}
asb.tabs(tabstops);
int ind = 0;
for (List<String> token : tokens) {
asb.style(AttributedStyle.DEFAULT).append(" ");
asb.style(compileStyle("token" + ind++, token.get(1)));
asb.append(token.get(0)).append("\t");
asb.append(token.get(1));
asb.style(AttributedStyle.DEFAULT).append("\t");
if ((ind % cols) == 0) {
asb.style(AttributedStyle.DEFAULT).append("\n");
}
}
asb.toAttributedString().println(terminal);
}
}
if (opt.isSet("list")) {
SyntaxHighlighter sh = SyntaxHighlighter.build(configPath.getConfig(DEFAULT_NANORC_FILE), null);
Path ct = sh.getCurrentTheme();
String parameter = replaceFileName(ct, "*" + TYPE_NANORCTHEME);
out.println(ct.getParent() + ":");
PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + parameter);
Files.find(Paths.get(new File(parameter).getParent()), Integer.MAX_VALUE
, (path, f) -> pathMatcher.matches(path))
.forEach(p -> out.println(p.getFileName()));

}
} catch (Exception e) {
err.println(e.getMessage());
}
}

private static void switchTheme(PrintStream err, Path config, String theme) {
try (Stream<String> stream = Files.lines(config, StandardCharsets.UTF_8)) {
List<String> list = stream.map(line -> line.matches("\\s*" + COMMAND_THEME +"\\s+.*")
? COMMAND_THEME + " " + theme : line).collect(Collectors.toList());
Files.write(config, list, StandardCharsets.UTF_8);
} catch (IOException e) {
err.println(e.getMessage());
}
}

private static String replaceFileName(Path path, String name) {
int nameLength = path.getFileName().toString().length();
int pathLength = path.toString().length();
Expand Down
5 changes: 2 additions & 3 deletions builtins/src/main/java/org/jline/builtins/Less.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@
import org.jline.utils.NonBlockingReader;
import org.jline.utils.Status;

import static org.jline.builtins.SyntaxHighlighter.COMMAND_INCLUDE;
import static org.jline.builtins.SyntaxHighlighter.COMMAND_THEME;
import static org.jline.builtins.SyntaxHighlighter.*;
import static org.jline.keymap.KeyMap.alt;
import static org.jline.keymap.KeyMap.ctrl;
import static org.jline.keymap.KeyMap.del;
Expand Down Expand Up @@ -146,7 +145,7 @@ public Less(Terminal terminal, Path currentDir, Options opts, ConfigurationPath
this.display = new Display(terminal, true);
this.bindingReader = new BindingReader(terminal.reader());
this.currentDir = currentDir;
Path lessrc = configPath != null ? configPath.getConfig("jlessrc") : null;
Path lessrc = configPath != null ? configPath.getConfig(DEFAULT_LESSRC_FILE) : null;
boolean ignorercfiles = opts!=null && opts.isSet("ignorercfiles");
if (lessrc != null && !ignorercfiles) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@
*/
public class SyntaxHighlighter {
public static final String REGEX_TOKEN_NAME = "[A-Z_]+";
public static final String TYPE_NANORCTHEME = ".nanorctheme";
public static final String DEFAULT_NANORC_FILE = "jnanorc";
protected static final String DEFAULT_LESSRC_FILE = "jlessrc";
protected static final String COMMAND_INCLUDE = "include";
protected static final String COMMAND_THEME = "theme";
protected static final String TYPE_NANORCTHEME = ".nanorctheme";
private static final String TOKEN_NANORC = "NANORC";
private final Path nanorc;
private final String syntaxName;
Expand Down
36 changes: 35 additions & 1 deletion console/src/main/java/org/jline/console/impl/Builtins.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
*/
package org.jline.console.impl;

import java.io.IOException;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;

import org.jline.builtins.Commands;
import org.jline.builtins.SyntaxHighlighter;
import org.jline.builtins.TTop;
import org.jline.builtins.Completers.FilesCompleter;
import org.jline.builtins.Completers.OptDesc;
Expand All @@ -31,6 +33,9 @@
import org.jline.reader.impl.completer.NullCompleter;
import org.jline.reader.impl.completer.StringsCompleter;

import static org.jline.builtins.SyntaxHighlighter.DEFAULT_NANORC_FILE;
import static org.jline.builtins.SyntaxHighlighter.TYPE_NANORCTHEME;

/**
* Builtins: create tab completers, execute and create descriptions for builtins commands.
*
Expand Down Expand Up @@ -93,7 +98,7 @@ public Builtins(Set<Command> commands, Supplier<Path> workDir, ConfigurationPath
commandExecute.put(Command.UNSETOPT, new CommandMethods(this::unsetopt, this::unsetoptCompleter));
commandExecute.put(Command.TTOP, new CommandMethods(this::ttop, this::defaultCompleter));
commandExecute.put(Command.COLORS, new CommandMethods(this::colors, this::defaultCompleter));
commandExecute.put(Command.HIGHLIGHTER, new CommandMethods(this::highlighter, this::defaultCompleter));
commandExecute.put(Command.HIGHLIGHTER, new CommandMethods(this::highlighter, this::highlighterCompleter));
registerCommands(commandName, commandExecute);
}

Expand Down Expand Up @@ -199,6 +204,35 @@ private List<String> unsetOptions(boolean set) {
return out;
}

private List<Completer> highlighterCompleter(String name) {
List<Completer> completers = new ArrayList<>();
List<OptDesc> optDescs = commandOptions(name);
for (OptDesc o : optDescs) {
if (o.shortOption() != null && (o.shortOption().equals("-v") || o.shortOption().equals("-s"))) {
Path userConfig = null;
if (o.shortOption().equals("-s")) {
try {
userConfig = configPath.getUserConfig(DEFAULT_NANORC_FILE);
} catch (IOException ignore) {
}
}
if (o.shortOption().equals("-v") || userConfig != null) {
Path ct = SyntaxHighlighter.build(configPath.getConfig(DEFAULT_NANORC_FILE), null)
.getCurrentTheme();
if (ct != null) {
o.setValueCompleter(new FilesCompleter(ct.getParent(), "*" + TYPE_NANORCTHEME));
}
}
}
}
completers.add(new ArgumentCompleter(NullCompleter.INSTANCE
, new OptionCompleter(NullCompleter.INSTANCE
, optDescs
, 1)
));
return completers;
}

private Set<String> allWidgets() {
Set<String> out = new HashSet<>();
for (String s: reader.getWidgets().keySet()) {
Expand Down

0 comments on commit 1aae0ae

Please sign in to comment.