Repository: microsoft/inshellisense
Pull request #293 (2024-10-24 18:21:51)

fix: path seperator logic when files are introduced
Fixes some errors in #291 with completing paths and added to the snapshots.


Patch:
diff --git a/src/runtime/model.ts b/src/runtime/model.ts
index c0e9a10..156fe13 100644
--- a/src/runtime/model.ts
+++ b/src/runtime/model.ts
@@ -8,7 +8,7 @@ export type Suggestion = {
   icon: string;
   priority: number;
   insertValue?: string;
-  pathy?: boolean;
+  type?: Fig.SuggestionType;
 };
 
 export type SuggestionBlob = {
diff --git a/src/runtime/parser.ts b/src/runtime/parser.ts
index 2e9a508..145a2d8 100644
--- a/src/runtime/parser.ts
+++ b/src/runtime/parser.ts
@@ -26,7 +26,7 @@ export const parseCommand = (command: string, shell: Shell): CommandToken[] => {
   return sanitizeTokens(tokens, shell);
 };
 
-const sanitizeTokens = (cmdTokens: CommandToken[], shell: Shell): CommandToken[] => unwrapQuotedTokens(unescapeSpaceTokens(cmdTokens, shell));
+const sanitizeTokens = (cmdTokens: CommandToken[], shell: Shell): CommandToken[] => unwrapQuotedTokens(unescapeSpaceTokens(cmdTokens, shell), shell);
 
 // remove escapes around spaces
 const unescapeSpaceTokens = (cmdTokens: CommandToken[], shell: Shell): CommandToken[] => {
@@ -41,12 +41,13 @@ const unescapeSpaceTokens = (cmdTokens: CommandToken[], shell: Shell): CommandTo
 };
 
 // need to unwrap tokens that are quoted with content after the quotes like `"hello"world`
-const unwrapQuotedTokens = (cmdTokens: CommandToken[]): CommandToken[] => {
+const unwrapQuotedTokens = (cmdTokens: CommandToken[], shell: Shell): CommandToken[] => {
+  const escapeChar = getShellWhitespaceEscapeChar(shell);
   return cmdTokens.map((cmdToken) => {
     const { token, isQuoteContinued } = cmdToken;
     if (isQuoteContinued) {
       const quoteChar = token[0];
-      const unquotedToken = token.replaceAll(`\\${quoteChar}`, "\u001B").replaceAll(quoteChar, "").replaceAll("\u001B", quoteChar);
+      const unquotedToken = token.replaceAll(`${escapeChar}${quoteChar}`, "\u001B").replaceAll(quoteChar, "").replaceAll("\u001B", quoteChar);
       return { ...cmdToken, token: unquotedToken };
     }
     return cmdToken;
diff --git a/src/runtime/suggestion.ts b/src/runtime/suggestion.ts
index ef72c6e..a4963f1 100644
--- a/src/runtime/suggestion.ts
+++ b/src/runtime/suggestion.ts
@@ -9,7 +9,7 @@ import { runTemplates } from "./template.js";
 import { Suggestion, SuggestionBlob } from "./model.js";
 import log from "../utils/log.js";
 import { escapePath } from "./utils.js";
-import { getPathSeparator, Shell } from "../utils/shell.js";
+import { addPathSeparator, getPathDirname, removePathSeparator, Shell } from "../utils/shell.js";
 
 export enum SuggestionIcons {
   File = "📄",
@@ -66,7 +66,7 @@ const toSuggestion = (suggestion: Fig.Suggestion, name?: string, type?: Fig.Sugg
     allNames: suggestion.name instanceof Array ? suggestion.name : [suggestion.name],
     priority: suggestion.priority ?? 50,
     insertValue: suggestion.insertValue,
-    pathy: getPathy(suggestion.type),
+    type: suggestion.type,
   };
 };
 
@@ -93,7 +93,7 @@ function filter<T extends Fig.BaseSuggestion & { name?: Fig.SingleOrArray<string
                   allNames: s.name,
                   priority: s.priority ?? 50,
                   insertValue: s.insertValue,
-                  pathy: getPathy(s.type),
+                  type: s.type,
                 }
               : undefined;
           }
@@ -105,7 +105,7 @@ function filter<T extends Fig.BaseSuggestion & { name?: Fig.SingleOrArray<string
                 allNames: [s.name],
                 priority: s.priority ?? 50,
                 insertValue: s.insertValue,
-                pathy: getPathy(s.type),
+                type: s.type,
               }
             : undefined;
         })
@@ -124,7 +124,7 @@ function filter<T extends Fig.BaseSuggestion & { name?: Fig.SingleOrArray<string
                   allNames: s.name,
                   insertValue: s.insertValue,
                   priority: s.priority ?? 50,
-                  pathy: getPathy(s.type),
+                  type: s.type,
                 }
               : undefined;
           }
@@ -136,7 +136,7 @@ function filter<T extends Fig.BaseSuggestion & { name?: Fig.SingleOrArray<string
                 allNames: [s.name],
                 insertValue: s.insertValue,
                 priority: s.priority ?? 50,
-                pathy: getPathy(s.type),
+                type: s.type,
               }
             : undefined;
         })
@@ -203,12 +203,13 @@ const optionSuggestions = (
 };
 
 function adjustPathSuggestions(suggestions: Suggestion[], partialToken: CommandToken | undefined, shell: Shell): Suggestion[] {
-  if (partialToken == null) return suggestions;
-
-  const sep = getPathSeparator(shell);
   return suggestions.map((s) => {
-    const fullPath = partialToken.isPath ? `${path.dirname(partialToken.token)}${sep}${s.insertValue}` : s.insertValue;
-    return s.pathy ? { ...s, insertValue: escapePath(fullPath, shell) } : s;
+    const pathy = getPathy(s.type);
+    const rawInsertValue = removePathSeparator(s.insertValue ?? s.name ?? "");
+    const insertValue = s.type == "folder" ? addPathSeparator(rawInsertValue, shell) : rawInsertValue;
+    const partialDir = getPathDirname(partialToken?.token ?? "", shell);
+    const fullPath = partialToken?.isPath ? `${partialDir}${insertValue}` : insertValue;
+    return pathy ? { ...s, insertValue: escapePath(fullPath, shell), name: removePathSeparator(s.name) } : s;
   });
 }
 
diff --git a/src/utils/shell.ts b/src/utils/shell.ts
index 212a58c..e28688e 100644
--- a/src/utils/shell.ts
+++ b/src/utils/shell.ts
@@ -145,6 +145,20 @@ export const getBackspaceSequence = (press: KeyPressEvent, shell: Shell) =>
 
 export const getPathSeparator = (shell: Shell) => (shell == Shell.Bash || shell == Shell.Xonsh || shell == Shell.Nushell ? "/" : path.sep);
 
+export const removePathSeparator = (dir: string) => {
+  return dir.endsWith("/") || dir.endsWith("\\") ? dir.slice(0, -1) : dir;
+};
+
+export const addPathSeparator = (dir: string, shell: Shell) => {
+  const pathSep = getPathSeparator(shell);
+  return dir.endsWith(pathSep) ? dir : dir + pathSep;
+};
+
+export const getPathDirname = (dir: string, shell: Shell) => {
+  const pathSep = getPathSeparator(shell);
+  return dir.endsWith(pathSep) || path.dirname(dir) == "." ? dir : addPathSeparator(path.dirname(dir), shell);
+};
+
 // nu fully re-writes the prompt every keystroke resulting in duplicate start/end sequences on the same line
 export const getShellPromptRewrites = (shell: Shell) => shell == Shell.Nushell;
 


Test patch:
diff --git a/src/tests/runtime/__snapshots__/parser.test.ts.snap b/src/tests/runtime/__snapshots__/parser.test.ts.snap
index 1d53b17..5f6d3ac 100644
--- a/src/tests/runtime/__snapshots__/parser.test.ts.snap
+++ b/src/tests/runtime/__snapshots__/parser.test.ts.snap
@@ -77,6 +77,44 @@ exports[`parseCommand cmd "value'\\"\\""  1`] = `
 ]
 `;
 
+exports[`parseCommand cmd 'item1\\item2\\'item3  1`] = `
+[
+  {
+    "complete": true,
+    "isOption": false,
+    "token": "cmd",
+    "tokenLength": 3,
+  },
+  {
+    "complete": true,
+    "isOption": false,
+    "isQuoteContinued": true,
+    "isQuoted": true,
+    "token": "item1\\item2\\item3",
+    "tokenLength": 19,
+  },
+]
+`;
+
+exports[`parseCommand cmd 'item1\\item2\\'item3 1`] = `
+[
+  {
+    "complete": true,
+    "isOption": false,
+    "token": "cmd",
+    "tokenLength": 3,
+  },
+  {
+    "complete": false,
+    "isOption": false,
+    "isQuoteContinued": true,
+    "isQuoted": true,
+    "token": "item1\\item2\\item3",
+    "tokenLength": 19,
+  },
+]
+`;
+
 exports[`parseCommand cmd 'value'  1`] = `
 [
   {
diff --git a/src/tests/runtime/__snapshots__/runtime.test.ts.snap b/src/tests/runtime/__snapshots__/runtime.test.ts.snap
index d138eca..458e76b 100644
--- a/src/tests/runtime/__snapshots__/runtime.test.ts.snap
+++ b/src/tests/runtime/__snapshots__/runtime.test.ts.snap
@@ -12,8 +12,8 @@ exports[`parseCommand alreadyUsedOption 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--bug-report",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
   ],
 }
@@ -33,8 +33,8 @@ exports[`parseCommand command 1`] = `
       "icon": "📦",
       "insertValue": undefined,
       "name": "stage",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -44,8 +44,8 @@ exports[`parseCommand command 1`] = `
       "icon": "📦",
       "insertValue": undefined,
       "name": "status",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -55,8 +55,8 @@ exports[`parseCommand command 1`] = `
       "icon": "📦",
       "insertValue": undefined,
       "name": "stash",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
   ],
 }
@@ -74,8 +74,8 @@ exports[`parseCommand completePrefixFilter 1`] = `
       "icon": "📦",
       "insertValue": undefined,
       "name": "status",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
   ],
 }
@@ -93,8 +93,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--artifact-server-path",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -104,8 +104,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--artifact-server-port",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -115,8 +115,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--container-architecture",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -126,8 +126,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--container-daemon-socket",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -138,8 +138,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--directory",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -150,8 +150,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--dryrun",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -161,8 +161,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--env-file",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -172,8 +172,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--github-instance",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -183,8 +183,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--insecure-secrets",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -194,8 +194,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--json",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -205,8 +205,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--no-recurse",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -216,8 +216,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--no-skip-checkout",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -228,8 +228,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--quiet",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -239,8 +239,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--secret-file",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -251,8 +251,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--verbose",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -263,8 +263,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--workflows",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -275,8 +275,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--help",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -286,8 +286,8 @@ exports[`parseCommand completedOptionWithArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--no-descriptions",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
   ],
 }
@@ -312,8 +312,8 @@ exports[`parseCommand exclusiveOnOption 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--nobreak",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -323,8 +323,8 @@ exports[`parseCommand exclusiveOnOption 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--nocolor",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -334,8 +334,8 @@ exports[`parseCommand exclusiveOnOption 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--nofilename",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -345,8 +345,8 @@ exports[`parseCommand exclusiveOnOption 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--nofollow",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -356,8 +356,8 @@ exports[`parseCommand exclusiveOnOption 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--nogroup",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -367,8 +367,8 @@ exports[`parseCommand exclusiveOnOption 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--noheading",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -378,8 +378,8 @@ exports[`parseCommand exclusiveOnOption 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--nommap",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -389,8 +389,8 @@ exports[`parseCommand exclusiveOnOption 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--nomultiline",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -401,8 +401,8 @@ exports[`parseCommand exclusiveOnOption 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--norecurse",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -412,8 +412,8 @@ exports[`parseCommand exclusiveOnOption 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--nonumbers",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
   ],
 }
@@ -431,8 +431,8 @@ exports[`parseCommand fullyTypedSuggestion 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "-W",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -442,8 +442,8 @@ exports[`parseCommand fullyTypedSuggestion 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "-w",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
   ],
 }
@@ -461,8 +461,8 @@ exports[`parseCommand generatorUsingPartialInput 1`] = `
       "icon": "📀",
       "insertValue": "Microsoft.Azure.WebJobs.Core",
       "name": "Microsoft.Azure.WebJobs.Core",
-      "pathy": false,
       "priority": 60,
+      "type": undefined,
     },
   ],
 }
@@ -480,8 +480,8 @@ exports[`parseCommand loadSpec 1`] = `
       "icon": "📦",
       "insertValue": undefined,
       "name": "add-tags-to-certificate",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
   ],
 }
@@ -499,8 +499,8 @@ exports[`parseCommand noArgsArgumentGiven 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--analyzer-output",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -510,8 +510,8 @@ exports[`parseCommand noArgsArgumentGiven 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "--analyze",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -521,8 +521,8 @@ exports[`parseCommand noArgsArgumentGiven 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "-arcmt-migrate-emit-errors",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
   ],
 }
@@ -546,10 +546,10 @@ exports[`parseCommand optionsSuggestedAfterVariadicArg 1`] = `
       ],
       "description": undefined,
       "icon": "📄",
-      "insertValue": undefined,
+      "insertValue": "package-lock.json",
       "name": "package-lock.json",
-      "pathy": true,
       "priority": 55,
+      "type": "file",
     },
     {
       "allNames": [
@@ -559,8 +559,8 @@ exports[`parseCommand optionsSuggestedAfterVariadicArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "-L",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -570,8 +570,8 @@ exports[`parseCommand optionsSuggestedAfterVariadicArg 1`] = `
       "icon": "🔗",
       "insertValue": undefined,
       "name": "-l",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
   ],
 }
@@ -589,8 +589,8 @@ exports[`parseCommand partialPrefixFilter 1`] = `
       "icon": "📦",
       "insertValue": undefined,
       "name": "stage",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -600,8 +600,8 @@ exports[`parseCommand partialPrefixFilter 1`] = `
       "icon": "📦",
       "insertValue": undefined,
       "name": "status",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
     {
       "allNames": [
@@ -611,8 +611,84 @@ exports[`parseCommand partialPrefixFilter 1`] = `
       "icon": "📦",
       "insertValue": undefined,
       "name": "stash",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
+    },
+  ],
+}
+`;
+
+exports[`parseCommand pathNestedSuggestion 1`] = `
+{
+  "charactersToDrop": 12,
+  "suggestions": [
+    {
+      "allNames": [
+        "workflows",
+      ],
+      "description": undefined,
+      "icon": "📁",
+      "insertValue": ".github/workflows/",
+      "name": "workflows",
+      "priority": 55,
+      "type": "folder",
+    },
+  ],
+}
+`;
+
+exports[`parseCommand pathSuggestion 1`] = `
+{
+  "charactersToDrop": 3,
+  "suggestions": [
+    {
+      "allNames": [
+        "shell",
+      ],
+      "description": undefined,
+      "icon": "📁",
+      "insertValue": "shell/",
+      "name": "shell",
+      "priority": 55,
+      "type": "folder",
+    },
+  ],
+}
+`;
+
+exports[`parseCommand pathWithFileFilteredSuggestion 1`] = `
+{
+  "charactersToDrop": 23,
+  "suggestions": [
+    {
+      "allNames": [
+        "shellIntegration.bash",
+      ],
+      "description": undefined,
+      "icon": "📄",
+      "insertValue": "shell/shellIntegration.bash",
+      "name": "shellIntegration.bash",
+      "priority": 55,
+      "type": "file",
+    },
+  ],
+}
+`;
+
+exports[`parseCommand pathWithFileSuggestion 1`] = `
+{
+  "charactersToDrop": 6,
+  "suggestions": [
+    {
+      "allNames": [
+        "bash-preexec.sh",
+      ],
+      "description": undefined,
+      "icon": "📄",
+      "insertValue": "shell/bash-preexec.sh",
+      "name": "bash-preexec.sh",
+      "priority": 55,
+      "type": "file",
     },
   ],
 }
@@ -628,10 +704,10 @@ exports[`parseCommand provideFileSuggestion 1`] = `
       ],
       "description": undefined,
       "icon": "📄",
-      "insertValue": undefined,
+      "insertValue": "README.md",
       "name": "README.md",
-      "pathy": true,
       "priority": 55,
+      "type": "file",
     },
   ],
 }
@@ -647,10 +723,10 @@ exports[`parseCommand provideFolderSuggestion 1`] = `
       ],
       "description": undefined,
       "icon": "📁",
-      "insertValue": undefined,
+      "insertValue": "src/",
       "name": "src",
-      "pathy": true,
       "priority": 55,
+      "type": "folder",
     },
   ],
 }
@@ -677,8 +753,8 @@ exports[`parseCommand providedSuggestion 1`] = `
       "icon": "📀",
       "insertValue": undefined,
       "name": "zsh",
-      "pathy": false,
       "priority": 50,
+      "type": undefined,
     },
   ],
 }
diff --git a/src/tests/runtime/parser.test.ts b/src/tests/runtime/parser.test.ts
index ee89193..ff40c1d 100644
--- a/src/tests/runtime/parser.test.ts
+++ b/src/tests/runtime/parser.test.ts
@@ -32,13 +32,15 @@ const testData = [
   { command: `cmd1 "item1"item2 item3` },
   { command: `cmd1 "item1"item2 "item3"` },
   { command: "`cmd1`" },
+  { command: "cmd 'item1\\item2\\'item3 ", shell: Shell.Powershell },
+  { command: "cmd 'item1\\item2\\'item3", shell: Shell.Powershell },
   { command: "😁" },
 ];
 
 describe(`parseCommand`, () => {
-  testData.forEach(({ command }) => {
+  testData.forEach(({ command, shell }) => {
     test(command, () => {
-      expect(parseCommand(command, Shell.Bash)).toMatchSnapshot();
+      expect(parseCommand(command, shell ?? Shell.Bash)).toMatchSnapshot();
     });
   });
 });
diff --git a/src/tests/runtime/runtime.test.ts b/src/tests/runtime/runtime.test.ts
index a65e563..a233a01 100644
--- a/src/tests/runtime/runtime.test.ts
+++ b/src/tests/runtime/runtime.test.ts
@@ -27,13 +27,17 @@ const testData = [
   { name: "loadSpec", command: "aws acm add" },
   { name: "noArgsArgumentGiven", command: "gcc lab ", maxSuggestions: 3 },
   { name: "generatorUsingPartialInput", command: "dotnet add package Microsoft.Azure.WebJobs.Cor", maxSuggestions: 1 },
+  { name: "pathSuggestion", command: "source she" },
+  { name: "pathNestedSuggestion", command: "source .github/work" },
+  { name: "pathWithFileSuggestion", command: "source shell/", maxSuggestions: 1 },
+  { name: "pathWithFileFilteredSuggestion", command: "source shell/shellIntegration.", maxSuggestions: 1 },
 ];
 
 describe(`parseCommand`, () => {
   testData.forEach(({ command, name, skip, maxSuggestions }) => {
     if (skip) return;
     test(name, async () => {
-      const suggestions = await getSuggestions(command, process.cwd(), Shell.Cmd);
+      const suggestions = await getSuggestions(command, process.cwd(), Shell.Bash);
       if (suggestions != null && suggestions.suggestions != null) {
         suggestions.suggestions = suggestions?.suggestions.slice(0, maxSuggestions);
       }
@@ -66,7 +70,7 @@ describe(`getCommandSuggestions`, () => {
   commandSuggestionsData.forEach(({ command, name, maxSuggestions, expectedNames, expectedIcons, platforms }) => {
     if (platforms != null && !platforms.includes(process.platform)) return;
     test(name, async () => {
-      const suggestions = await getSuggestions(command, process.cwd(), Shell.Cmd);
+      const suggestions = await getSuggestions(command, process.cwd(), Shell.Bash);
       if (suggestions != null && suggestions.suggestions != null) {
         suggestions.suggestions = suggestions?.suggestions.slice(0, maxSuggestions);
       }