Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Something odd with backslashes and completion #173

Closed
tomq42 opened this issue Sep 19, 2017 · 8 comments
Closed

Something odd with backslashes and completion #173

tomq42 opened this issue Sep 19, 2017 · 8 comments
Milestone

Comments

@tomq42
Copy link

tomq42 commented Sep 19, 2017

I'm trying to write a simple jline completer that will help me enter a filename, so it will take the current line as a path, list the files, and so on. I can write the completer I want, I'm just getting very odd behaviour with backslashes.
I'm running on Windows, and actually doing this through karaf (I haven't actually been able to create a simple standalone example of running jline of ANY kind, a simple working hello world example would be really good).

If I type "c:/" (note forward slash) at the prompt and tab, my completer gets called, and I correctly get a displayed list of all files in c:. If however I type "c:" instead (backslash) then I get a listing, but what I've typed has been replaced by "cc:". All completion then fails. If I type in, say, "c:\work" (a valid path), my completer gets called, but nothing is displayed. So backslashes appear to make it all go wrong.

My completer is:

	@Override
    public void complete(LineReader reader, ParsedLine commandLine, final List<Candidate> candidates) {
		String line = commandLine.line();
		
		File[] filenames;
		if (line.endsWith("/") || line.endsWith("\\")) {
			filenames = new File(line).listFiles();
		}
		else {
			File f = new File(line);
			String partialUpper = f.getName().toUpperCase();
			f = f.getParentFile();
			filenames = Arrays.stream(f.listFiles()).
					filter(fileName->fileName.getName().toUpperCase().startsWith(partialUpper)).
					toArray(File[]::new);
		}
		
		String sep = System.getProperty("file.separator");
		Arrays.stream(filenames).forEach(fileName->{
			candidates.add(new Candidate(
					fileName.toString().replace('\\', '/'), 
					fileName.getName(), 
					null, null, 
					fileName.isDirectory() ? sep : null,
					null,
					fileName.isDirectory() ? false : true));
		});
    }

I'm setting lineReader.setOpt(LineReader.Option.DISABLE_EVENT_EXPANSION); in an attempt to avoid backslashes being replaced.

@gnodet
Copy link
Member

gnodet commented Sep 19, 2017

I think you need to configure a parser to suit your needs.
The default parser can be configured using

DefaultParser parser = new DefaultParser();
parser.setEscapeChars(null);
...
lineReaderBuilder.parser(parser);

@gnodet
Copy link
Member

gnodet commented Sep 22, 2017

Please reopen if needed

@gnodet gnodet closed this as completed Sep 22, 2017
@tomq42
Copy link
Author

tomq42 commented Sep 22, 2017

Yes, sure I can work round the issue.
But I can't believe that the behaviour of replacing "c:" with "cc:" (I type "c colon backslash", and it gets changed to "c c colon backslash") and hence rendering the filename incorrect is what's supposed to happen.

@gnodet
Copy link
Member

gnodet commented Sep 22, 2017

I think the problem is in your completer.
First, the completer should only complete the last word of the parsed command line. Then, the candidates should be full words for the currently being completed word.
So if you are completing C:\, the candidates should be C:\Users, C:\Program Files, not Users, etc..
Could you set up a unit test with a fake completer that would demonstrate the problem ?
See https://github.com/jline/jline3/blob/master/reader/src/test/java/org/jline/reader/completer/StringsCompleterTest.java for a simple completion test. You can add a test to that class with a custom completer.

@gnodet gnodet reopened this Sep 22, 2017
@Victor9401
Copy link

Victor9401 commented Nov 29, 2017

Hello. Can confirm this behavior

It caused by two things:

DefaultParser in reader lists \ as escape char (normal for Unix terminals, but not for windows), so when parser splits string "c:\" into ParsedLine, it has just one word "c:" without trailing \. So when completer tries to rewrite string, it clears last word (2 chars), and writes candidate (1st word) and it becomes "cc:".
It could be fixed with clearing escape chars in parser object and then passing it to LineReader, but you must be sure that you understand what you do. It can cause strange behavior on Unix like terminals.

Second one is caused by default FileNameCompleter.
It uses File.separator property just once. On the other lines "\" is hard coded. That's a bug for now.

@Victor9401
Copy link

Victor9401 commented Nov 29, 2017

Ok, so just haven't read this issue properly. I think I should create new one for the second part, because this issue is not about it...

@Locke
Copy link

Locke commented Mar 1, 2018

Second one is caused by default FileNameCompleter.
It uses File.separator property just once. On the other lines "\" is hard coded. That's a bug for now.

I can confirm this. I think a new issue would be better to track that. As parsing "\" from the input requires parser.setEscapeChars(null); I'd suggest to use the unix style "/" also on windows, just to make it easier to use.

@gnodet
Copy link
Member

gnodet commented Apr 6, 2018

This should have been affected by #245

@gnodet gnodet added this to the 3.7.0 milestone Apr 6, 2018
gnodet added a commit that referenced this issue Apr 8, 2018
@gnodet gnodet closed this as completed Apr 11, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants