public static List <Suggestion> GetCompletions(string sanitizedText, API.Shell shell, int cursorPos) { var INVOKE_IN_DIR = "." + Path.DirectorySeparatorChar; var executableSanitizedInput = sanitizedText.Remove(0, INVOKE_IN_DIR.Length); var basePath = shell.WorkingDirectory; var startOfFilename = executableSanitizedInput; var lastDir = executableSanitizedInput.LastIndexOf(Path.DirectorySeparatorChar); if (lastDir != -1) { basePath = Path.Combine(basePath, executableSanitizedInput.Substring(0, lastDir)); startOfFilename = executableSanitizedInput.Remove(0, lastDir + 1); } return(GetFilesAndFolders(basePath) .Where(x => x.StartsWith(startOfFilename)) // TODO we should check if the executable bit is set here .Distinct() .Select(x => new Suggestion() { Index = cursorPos, CompletionText = x.Remove(0, startOfFilename.Length), FullText = x }) .ToList()); }
internal static string ConvertToAbsolute(string dir, API.Shell shell) { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { dir = dir.Replace("~", shell.HomeDirectory); if (!dir.StartsWith(Path.DirectorySeparatorChar)) { dir = Path.Combine(shell.WorkingDirectory, dir); } return(Path.GetFullPath(dir)); } else { return(Path.GetFullPath(dir.Replace("~", shell.HomeDirectory), shell.WorkingDirectory)); } }
private static List <Suggestion> GetMatchingFilesOrDirectories(string sanitizedText, API.Shell shell, int cursorPos) { // 'command arg1 arg2 /home/asdad/d<TAB>' var fsStart = sanitizedText.LastIndexOf(' ', sanitizedText.Length - 1); // todo change to regex and match multiple chars? var startOfDirOrFile = sanitizedText.Remove(0, fsStart == -1 ? 0 : fsStart + 1); // +1 for the space var fullPath = ConvertToAbsolute(startOfDirOrFile, shell); var directoryName = Path.GetDirectoryName(fullPath); if (directoryName == null) { directoryName = Dotnet.Shell.API.Shell.BasePath; } var toMatch = Path.GetFileName(fullPath); // /ho<TAB> // ./home<TAB> // ../<TAB> // bob/asdads<TAB> // suggest a file or directory List <string> items = new(); try { items.AddRange(Directory.GetFiles(directoryName).Select(x => Path.GetFileName(x))); } catch { } try { items.AddRange(Directory.GetDirectories(directoryName).Select(x => Path.GetFileName(x) + Path.DirectorySeparatorChar)); } catch { } return(items .Where(x => string.IsNullOrWhiteSpace(toMatch) || x.StartsWith(toMatch)) .Select(x => x.Remove(0, toMatch.Length)) .Distinct() .Select(x => new Suggestion() { Index = cursorPos, CompletionText = x, FullText = toMatch + x }).ToList()); }
public static async Task <List <Suggestion> > GetCompletionsAsync(string sanitizedText, API.Shell shell, int cursorPos, Task <string[]> commandsInPath) { // if our cursor position is before a space then we are in command completion mode // otherwise we will complete with a filename // need to decide if we are going to look for a command, or a file var spacePos = sanitizedText.IndexOf(' '); bool suggestCommand = spacePos == -1 || spacePos >= cursorPos; if (suggestCommand) { #pragma warning disable VSTHRD003 // Avoid awaiting foreign Tasks var matchedEndings = (await commandsInPath).Where(x => x.StartsWith(sanitizedText)).Select(x => x.Remove(0, sanitizedText.Length)).Distinct().ToList(); #pragma warning restore VSTHRD003 // Avoid awaiting foreign Tasks return(matchedEndings .ConvertAll(x => new Suggestion() { CompletionText = x, Index = cursorPos, FullText = sanitizedText + x }) .Union(GetMatchingFilesOrDirectories(sanitizedText, shell, cursorPos)) .Distinct() .ToList()); } else { return(GetMatchingFilesOrDirectories(sanitizedText, shell, cursorPos)); } }
public static List <Suggestion> GetCompletions(string sanitizedText, API.Shell shell, int cursorPos) { const string CD_MATCH = "cd"; var cdSanitizedInput = sanitizedText.Remove(0, CD_MATCH.Length).TrimStart(); bool isAbsolutePath = cdSanitizedInput.StartsWith(Path.DirectorySeparatorChar) || RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && cdSanitizedInput.Length >= 3 && cdSanitizedInput[1] == ':'; if ((isAbsolutePath && Directory.Exists(cdSanitizedInput) && !cdSanitizedInput.EndsWith(Path.DirectorySeparatorChar)) || (Directory.Exists(Path.Combine(shell.WorkingDirectory, cdSanitizedInput)) && !cdSanitizedInput.EndsWith(Path.DirectorySeparatorChar))) { // Directories must end with a slash return(new List <Suggestion>() { new Suggestion() { Index = cursorPos, CompletionText = Path.DirectorySeparatorChar.ToString(), FullText = cdSanitizedInput + Path.DirectorySeparatorChar } }); } if (string.IsNullOrWhiteSpace(cdSanitizedInput) || (isAbsolutePath && Directory.Exists(cdSanitizedInput))) { return (TryGetDirectories(isAbsolutePath ? cdSanitizedInput : shell.WorkingDirectory) .Select(x => new Suggestion() { Index = cursorPos, CompletionText = Path.GetFileName(x) + Path.DirectorySeparatorChar, FullText = Path.GetFileName(x) + Path.DirectorySeparatorChar }) .ToList()); } else if (isAbsolutePath) // absolute paths { return (TryGetDirectories(Path.GetDirectoryName(cdSanitizedInput)) .Where(x => x.StartsWith(cdSanitizedInput)) .Select(x => x.Remove(0, cdSanitizedInput.Length)) .Distinct() .Select(x => new Suggestion() { Index = cursorPos, CompletionText = x + Path.DirectorySeparatorChar, FullText = cdSanitizedInput + x + Path.DirectorySeparatorChar }) .ToList()); } else if (cdSanitizedInput.Contains(Path.DirectorySeparatorChar)) // sub directories based on CWD { var dirName = Path.GetFileName(cdSanitizedInput); return (TryGetDirectories(Path.Combine(shell.WorkingDirectory, Path.GetDirectoryName(cdSanitizedInput))) .Select(x => Path.GetFileName(x)) .Where(x => x.StartsWith(dirName)) .Select(x => x.Remove(0, dirName.Length)) .Distinct() .Select(x => new Suggestion() { Index = cursorPos, CompletionText = x + Path.DirectorySeparatorChar, FullText = cdSanitizedInput + x + Path.DirectorySeparatorChar }) .ToList()); } else // based from working dir { return(TryGetDirectories(shell.WorkingDirectory) .Select(x => Path.GetFileName(x)) .Where(x => x.StartsWith(cdSanitizedInput)) .Select(x => x.Remove(0, cdSanitizedInput.Length)) .Distinct() .Select(x => new Suggestion() { Index = cursorPos, CompletionText = x + Path.DirectorySeparatorChar, FullText = cdSanitizedInput + x + Path.DirectorySeparatorChar }) .ToList()); } }
public CmdSuggestions(API.Shell shell, Task <string[]> commandsInPath) { this.shell = shell; this.commandsInPath = commandsInPath; }
internal CmdSuggestions(API.Shell shell) { this.shell = shell; this.commandsInPath = Task.FromResult(Array.Empty <string>()); }