Skip to content
This repository was archived by the owner on May 21, 2019. It is now read-only.

Commit 681603f

Browse files
committed
Suggest relative executables for command word.
1 parent 235a520 commit 681603f

File tree

7 files changed

+40
-11
lines changed

7 files changed

+40
-11
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"fuzzaldrin": "2.1.0",
3434
"immutable": "3.8.1",
3535
"lodash": "4.13.1",
36+
"mode-to-permissions": "0.0.2",
3637
"node-ansiparser": "2.1.0",
3738
"pty.js": "shockone/pty.js",
3839
"react": "15.1.0",

src/PluginManager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import {OutputDecorator, EnvironmentObserverPlugin, AutocompletionProvider, Pree
22
import * as Path from "path";
33
import {recursiveFilesIn} from "./utils/Common";
44
import {
5-
anyFilesSuggestions, environmentVariableSuggestions,
5+
anyFilesSuggestionsProvider, environmentVariableSuggestions,
66
combineAutocompletionProviders,
77
} from "./plugins/autocompletion_providers/Common";
88

9-
const defaultAutocompletionProvider = combineAutocompletionProviders([environmentVariableSuggestions, anyFilesSuggestions]);
9+
const defaultAutocompletionProvider = combineAutocompletionProviders([environmentVariableSuggestions, anyFilesSuggestionsProvider]);
1010

1111
// FIXME: Technical debt: register all the plugin types via single method.
1212
export class PluginManager {

src/plugins/autocompletion_providers/Cd.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {expandHistoricalDirectory} from "../../Command";
22
import {styles, Suggestion} from "./Suggestions";
33
import * as _ from "lodash";
4-
import {directoriesSuggestions} from "./Common";
4+
import {directoriesSuggestionsProvider} from "./Common";
55
import {PluginManager} from "../../PluginManager";
66

77
PluginManager.registerAutocompletionProvider("cd", async(context) => {
@@ -14,12 +14,12 @@ PluginManager.registerAutocompletionProvider("cd", async(context) => {
1414
suggestions.push(...historicalDirectoryAliases);
1515
}
1616

17-
suggestions.push(...await directoriesSuggestions(context));
17+
suggestions.push(...await directoriesSuggestionsProvider(context));
1818

1919
if (context.argument.value.length > 0) {
2020
const cdpathDirectories = _.flatten(await Promise.all(context.environment.cdpath
2121
.filter(directory => directory !== context.environment.pwd)
22-
.map(async(directory) => (await directoriesSuggestions(context, directory)).map(suggestion => suggestion.withDescription(`In ${directory}`)))));
22+
.map(async(directory) => (await directoriesSuggestionsProvider(context, directory)).map(suggestion => suggestion.withDescription(`In ${directory}`)))));
2323

2424
suggestions.push(...cdpathDirectories);
2525
}

src/plugins/autocompletion_providers/Common.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ import {statsIn, resolveDirectory, directoryName} from "../../utils/Common";
22
import {styles, Suggestion} from "./Suggestions";
33
import {FileInfo, SuggestionContext, AutocompletionProvider} from "../../Interfaces";
44
import * as Path from "path";
5+
import * as modeToPermissions from "mode-to-permissions";
56

67
function escapePath(path: string) {
78
return path.replace(/\s/g, "\\ ");
89
}
910

10-
export const filesSuggestions = (filter: (info: FileInfo) => boolean) => async(context: SuggestionContext, directory = context.environment.pwd): Promise<Suggestion[]> => {
11-
const tokenDirectory = directoryName(context.argument.value);
11+
const filesSuggestions = (filter: (info: FileInfo) => boolean) => async(tokenValue: string, directory: string): Promise<Suggestion[]> => {
12+
const tokenDirectory = directoryName(tokenValue);
1213
const directoryPath = resolveDirectory(directory, tokenDirectory);
1314
const stats = await statsIn(directoryPath);
1415

15-
return stats.filter(filter).map(info => {
16+
return stats.filter(info => info.stat.isDirectory() || filter(info)).map(info => {
1617
if (info.stat.isDirectory()) {
1718
return new Suggestion().withValue(escapePath(Path.join(tokenDirectory, info.name + Path.sep))).withDisplayValue(info.name + Path.sep).withStyle(styles.directory);
1819
} else {
@@ -21,8 +22,14 @@ export const filesSuggestions = (filter: (info: FileInfo) => boolean) => async(c
2122
});
2223
};
2324

24-
export const anyFilesSuggestions = filesSuggestions(() => true);
25-
export const directoriesSuggestions = filesSuggestions(info => info.stat.isDirectory());
25+
const filesSuggestionsProvider =
26+
(filter: (info: FileInfo) => boolean) =>
27+
(context: SuggestionContext, directory = context.environment.pwd): Promise<Suggestion[]> =>
28+
filesSuggestions(filter)(context.argument.value, directory);
29+
30+
export const executableFilesSuggestions = filesSuggestions(info => info.stat.isFile() && modeToPermissions(info.stat.mode).execute.owner);
31+
export const anyFilesSuggestionsProvider = filesSuggestionsProvider(() => true);
32+
export const directoriesSuggestionsProvider = filesSuggestionsProvider(info => info.stat.isDirectory());
2633

2734
export const environmentVariableSuggestions = async(context: SuggestionContext): Promise<Suggestion[]> => {
2835
if (context.argument.value.startsWith("$")) {

src/references.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/// <reference path="../typings/Overrides.d.ts" />
22
/// <reference path="../typings/Interfaces.d.ts" />
33

4+
/// <reference path="../typings/mode-to-permissions.d.ts" />
5+
46
/// <reference path="../node_modules/immutable/dist/immutable.d.ts" />

src/shell/Parser.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {PluginManager} from "../PluginManager";
1010
import {Aliases} from "../Aliases";
1111
import {
1212
environmentVariableSuggestions,
13-
combineAutocompletionProviders,
13+
combineAutocompletionProviders, executableFilesSuggestions,
1414
} from "../plugins/autocompletion_providers/Common";
1515

1616
export abstract class ASTNode {
@@ -116,12 +116,14 @@ class CommandWord extends LeafNode {
116116
return [];
117117
}
118118

119+
const relativeExecutablesSuggestions = await executableFilesSuggestions(this.value, context.environment.pwd);
119120
const executables = await executablesInPaths(context.environment.path);
120121

121122
return [
122123
...mapObject(context.aliases.toObject(), (key, value) => new Suggestion().withValue(`${key} `).withDescription(value).withStyle(styles.alias)),
123124
...loginShell.preCommandModifiers.map(modifier => new Suggestion().withValue(`${modifier} `).withStyle(styles.func)),
124125
...executables.map(name => new Suggestion().withValue(`${name} `).withDescription(commandDescriptions[name] || "").withStyle(styles.executable)),
126+
...relativeExecutablesSuggestions,
125127
];
126128
}
127129
}

typings/mode-to-permissions.d.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
interface PermittedGroups {
2+
owner: boolean;
3+
group: boolean;
4+
others: boolean;
5+
}
6+
7+
interface Permissions {
8+
read: PermittedGroups;
9+
write: PermittedGroups;
10+
execute: PermittedGroups;
11+
}
12+
13+
declare module "mode-to-permissions" {
14+
function modeToPermissions(mode: number): Permissions;
15+
namespace modeToPermissions {}
16+
export = modeToPermissions;
17+
}

0 commit comments

Comments
 (0)