AutocompleteFilepathContext.cs 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. using System.IO.Abstractions;
  2. using System.Runtime.InteropServices;
  3. namespace Terminal.Gui;
  4. internal class AutocompleteFilepathContext : AutocompleteContext
  5. {
  6. public AutocompleteFilepathContext (string currentLine, int cursorPosition, FileDialogState state)
  7. : base (Cell.ToCellList (currentLine), cursorPosition)
  8. {
  9. State = state;
  10. }
  11. public FileDialogState State { get; set; }
  12. }
  13. internal class FilepathSuggestionGenerator : ISuggestionGenerator
  14. {
  15. private FileDialogState state;
  16. public IEnumerable<Suggestion> GenerateSuggestions (AutocompleteContext context)
  17. {
  18. if (context is AutocompleteFilepathContext fileState)
  19. {
  20. state = fileState.State;
  21. }
  22. if (state is null)
  23. {
  24. return Enumerable.Empty<Suggestion> ();
  25. }
  26. var path = Cell.ToString (context.CurrentLine);
  27. int last = path.LastIndexOfAny (FileDialog.Separators);
  28. if (string.IsNullOrWhiteSpace (path) || !Path.IsPathRooted (path))
  29. {
  30. return Enumerable.Empty<Suggestion> ();
  31. }
  32. string term = path.Substring (last + 1);
  33. // If path is /tmp/ then don't just list everything in it
  34. if (string.IsNullOrWhiteSpace (term))
  35. {
  36. return Enumerable.Empty<Suggestion> ();
  37. }
  38. if (term.Equals (state?.Directory?.Name))
  39. {
  40. // Clear suggestions
  41. return Enumerable.Empty<Suggestion> ();
  42. }
  43. bool isWindows = RuntimeInformation.IsOSPlatform (OSPlatform.Windows);
  44. string [] suggestions = state.Children.Where (d => !d.IsParent)
  45. .Select (
  46. e => e.FileSystemInfo is IDirectoryInfo d
  47. ? d.Name + Path.DirectorySeparatorChar
  48. : e.FileSystemInfo.Name
  49. )
  50. .ToArray ();
  51. string [] validSuggestions = suggestions
  52. .Where (
  53. s => s.StartsWith (
  54. term,
  55. isWindows
  56. ? StringComparison.InvariantCultureIgnoreCase
  57. : StringComparison.InvariantCulture
  58. )
  59. )
  60. .OrderBy (m => m.Length)
  61. .ToArray ();
  62. // nothing to suggest
  63. if (validSuggestions.Length == 0 || validSuggestions [0].Length == term.Length)
  64. {
  65. return Enumerable.Empty<Suggestion> ();
  66. }
  67. return validSuggestions.Select (
  68. f => new Suggestion (term.Length, f, f)
  69. )
  70. .ToList ();
  71. }
  72. public bool IsWordChar (Rune rune)
  73. {
  74. if (rune.Value == '\n')
  75. {
  76. return false;
  77. }
  78. return true;
  79. }
  80. }