Skip to content

Commit

Permalink
Added the fcd-config command/feature
Browse files Browse the repository at this point in the history
  • Loading branch information
SiddharthShyniben committed Apr 19, 2021
1 parent 6a73dbc commit 80e54be
Show file tree
Hide file tree
Showing 10 changed files with 691 additions and 532 deletions.
5 changes: 3 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Please note we have a code of conduct, please follow it in all your interactions

Don't know what to contribute? Here's a todo list for everyone (and myself):

- [ ] Add config support
- [x] Add config support
- See [`conf`](https://github.com/sindresorhus/conf)
- [x] Relative paths are broken
- [x] Fix Relative paths
- [ ] Caching?
79 changes: 70 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,18 @@ You need to have [Node.js][node-url] (and npm) installed.
### Installation

1. Install using npm
```sh
npm i -g fcd
```console
$ npm i -g fcd
```
2. Be more productive :smile:
```sh
fcd ./project
```console
$ fcd ./project
```

<!-- USAGE EXAMPLES -->
## Usage

```sh
```console
$ fcd path/to/search/foldername-to-search-for
```

Expand All @@ -123,17 +123,78 @@ The usage of this cli is very simple. It boasts two commands:

### `fcd`

`fcd` takes one argument `"path"` to search. You can optionally use the `"-v"`/`"--verbose"` command to run it in verbose mode, which shows you all the searched folders.
`fcd` takes one argument `"path"` to search. You can optionally use the `"-v"`/`"--verbose"` option to run it in verbose mode, which shows you all the searched folders.

Example:

```sh
fcd path -v
```console
$ fcd path -v
```

### `fcd-config`

Coming soon
The `fcd-config` command is used to configure the `fcd` command. It currently has only configurable three options:

* `ignoredFolders`: List of folders to be ignored. Defaults to `node_modules,Trash,Library`
* `ignoreDotFolders`: Whether to ignore `.folders` like `.git` or `.bin`. Defaults to `true`
* `addNewlineToCopy`: Whether to add a newline to the copied `cd` command. When set to `true`, the copied `cd` command will automatically run when pasted and vice-versa. Defaults to `true`

There are quite a few sub-commands, namely:

* `get <key>`: Used to get the value of a configuration.

Example:
```console
$ fcd-config get ignoredFolders
fcd SUC! `ignoredFolders`: `["Trash","node_modules","Library"]`
$ fcd-config get ignoreDotFolders
fcd SUC! `ignoreDotFolders`: `true`
```
* `set <key> <value>`: Used to set the value of a configuration.

`set`ting completely overwrites the previous configuration. If you meant to add a value to, for example, `ignoredFolders` use the `add` command.

Example:
```console
$ fcd-config set ignoredFolders Trash,node_modules,Library,Music
fcd WARN! Setting array values directly will overwrite all values
fcd WARN! not add to them. Use the add command if you meant to add
fcd SUC! Set `ignoredFolders` to `Trash,node_modules,Library,Music`
$ fcd-config set ignoreDotFolders false
fcd SUC! Set `ignoreDotFolders` to `false`
```
* `add <key> <values...>`: Used to add a value to a configuration with an array as a value.

This command can currently be used only for the `ignoreDotFolders` setting. If you set any other property using this command, that setting will become `false`, even if the success message does not say so.
<!-- I didn't mean to, but yeah, I got lazy -->

Example:
```console
$ fcd-config add ignoredFolders Music
fcd SUC! Added `Music` to `ignoredFolders`
$ fcd-config add ignoreDotFolders true
fcd SUC! Added `true` to `ignoreDotFolders`
$ fcd-config get ignoreDotFolders
fcd SUC! `ignoreDotFolders`: `false`
```
* `path`: Used to get the path to the configuration file (JSON)

Example:
```console
$ fcd-config path
fcd SUC! Path: `/Users/apple/Library/Preferences/fcd-nodejs/config.json`
```
* `reset [keys...]`: Used to reset all keys **or** the provided keys to their default values

Example:
```console
$ fcd-config reset ignoredFolders
fcd SUC! `ignoredFolders` reset successfully
$ fcd-config reset ignoredFolders,ignoreDotFolders
fcd SUC! `ignoredFolders,ignoreDotFolders` reset successfully
$ fcd-config reset
fcd SUC! Config reset successfully
```



Expand Down
44 changes: 30 additions & 14 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,33 @@ const ora = require("ora");
const path = require("path");

const messenger = require("./messenger");
const { ignoredFolders, standardizePath } = require("./utils");
const config = require("./config");

let spinner;

const handler = exports.handler = (input, verbose) => {
const standardizePath = module.exports.standardizePath = input => {
if (!input) return;

const tildeExpander = require("tilde-expansion");

// Normalize path ("~/Assets/../Files" => "~/Files") + Remove trailing slashes
input = path.resolve(input).replace(/\/+$/, "");

// Expand tildes ("~/Somewhere" => "/Users/<username>/Somewhere")
tildeExpander(input, expanded => input = expanded);

// Return dirname, foldername
return { dirname: path.dirname(input), basename: path.basename(input) }
};

const handler = module.exports.handler = (input, verbose) => {
if (verbose) messenger.info("Verbose mode on", "");

input = standardizePath(input);

if (input) {
let folders = [];
const ignoredFolders = config.ignoredFolders || ["Trash", "Library", "node_modules"];

if (!verbose) spinner = ora("Searching...").start();

Expand All @@ -27,20 +43,20 @@ const handler = exports.handler = (input, verbose) => {

if (ignoredFolders.includes(base)) {
stopǃ(); // Love the exclamation? No? Ok delete it if you want ಠ_ಠ (PS: ಠ_ಠ is also a valid JavaScript variable name)
verbose ? messenger.info(`Searching ${dir} aborted (ignored folder)`) : spinner.text += ' aborted (ignored folder)';
verbose ? messenger.info(`Searching ${dir} aborted (ignored folder)`) : spinner.text += " aborted (ignored folder)";
}

if (base.startsWith(".") && base !== ".") {
if (config.ignoreDotFolders && base.startsWith(".") && base !== ".") {
stopǃ();
verbose ? messenger.info(`Searching ${dir} aborted (dot folder)`) : spinner.text += ' aborted (dot folder)';
verbose ? messenger.info(`Searching ${dir} aborted (dot folder)`) : spinner.text += " aborted (dot folder)";
}

if (path.basename(dir) == input.basename) folders.push(dir);
});

finder.on("end", () => {
if (!verbose) spinner.succeed("Search complete");
else messenger.info("", "Search complete");
else messenger.success("", "Search complete");

// Now ask user where to cd and then cd
askAndCD(folders, input.dirname);
Expand All @@ -52,27 +68,27 @@ const handler = exports.handler = (input, verbose) => {

const askAndCD = async (basesFound, dirname) => {
if (basesFound.length == 0) {
messenger.error("Folder not found");
messenger.warn("Folder not found");
} else if (basesFound.length == 1) {
cd(basesFound[0]);
} else {
const { Select } = require('enquirer');
const { Select } = require("enquirer");

const prompt = new Select({
name: 'folder',
message: 'Pick a folder to cd into',
name: "folder",
message: "Pick a folder to cd into",
choices: basesFound
});

prompt.run()
.then(answer => cd(answer, dirname))
.catch(messenger.error);
.catch(() => {});
}
};

const cd = (basename, dirname) => {
const clipboard = require("clipboardy");
// write "cd (dirname or .)/basename(newline \n)"
clipboard.write("cd " + (dirname ? dirname : "") + basename + "\n")
.then(() => messenger.info("Command copied to clipboard successfully"));
// write "cd (dirname or .)/basename(\n if preferred)"
clipboard.write(`cd ${dirname || ""}${basename}${config.addNewlineToCopy ? "\n" : ""}`)
.then(() => messenger.success("Command copied to clipboard successfully"));
};
83 changes: 83 additions & 0 deletions bin/config-cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env node

const config = require("./config");
const messenger = require("./messenger");

const yargs = require("yargs")
.scriptName("fcd-config")

.command(
"get <key>",
"Get the value of a key",
yarg => yarg
.positional("key", { describe: "Key to get", type: "string" })
.example("$0 get ignoredFolders", "get the list of ignored folders"),
args => {
let data = config[args.key];

if (data !== undefined) messenger.success(`\`${args.key}\`: \`${JSON.stringify(data)}\``)
else messenger.error(`Unknown key: ${args.key}`);
}
)

.command(
"set <key> <value>",
"Set a configuration",
yarg => yarg
.positional("key", { describe: "Key to set", type: "string" })
.positional("value", { describe: "Value to set", type: "string" })
.example("$0 set ignoreDotFolders true", "set `ignoreDotFolders` to `true`")
.example("$0 set ignoredFolders Trash,Library,node_modules,Music", "set (rewrite the whole) `ignoredFolders` to `Trash,Library,node_modules,Music`"),
args => {
if (args.value.search(",") !== -1) messenger.warn("Setting array values directly will overwrite all values", "not add to them. Use the add command if you meant to add");

if (config[args.key] !== undefined) {
config[args.key] = args.value;
messenger.success(`Set \`${args.key}\` to \`${args.value}\``);
} else messenger.error(`Unknown key: \`${args.key}\``);
}
)

.command(
"add <key> <values...>",
"Add to a configuration with the array type",
yarg => yarg
.positional("key", { describe: "Key to set", type: "string" })
.positional("values", { describe: "Value(s) to set", type: "string" })
.example("$0 add ignoredFolders Music", "`Music` will be added to the ignored folders")
.example("$0 add ignoreDotFolders true", "This will make `ignoreDotFolders` `false` because it is not an array"),
args => {
if (config[args.key] !== undefined) {
const older = config[args.key];
older.push?.(...args.values)
config[args.key] = older.join?.();
messenger.success(`Added \`${args.values.join()}\` to \`${args.key}\``);
} else messenger.error(`Unknown key: \`${args.key}\``);
}
)

.command(
"path",
"Get the path to the config file",
yarg => yarg.example("$0 path", "get the path to the config file"),
() => messenger.success(`Path: \`${config.path}\``)
)

.command(
"reset [keys...]",
"Reset all keys or given keys",
yarg => yarg
.example("$0 reset ignoredFolders ignoreDotFolders", "reset \`ignoredFolders\` and \`ignoreDotFolders\`")
.example("$0 reset", "reset everything"),
argv => {
argv.keys ? config.reset(...argv.keys) : config.clear()
messenger.success(`${argv.keys ? "`" + argv.keys.join() +"`" : "Config"} reset successfully`)
}
)

.recommendCommands()
.help()
.wrap(null)
// .locale("pirate")
.epilogue("For more documentation, visit the github repo at https://github.com/SiddharthShyniben/fcd")
.argv
64 changes: 64 additions & 0 deletions bin/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const Conf = require("conf");

// More like a reference for myself
const config = new Conf({
defaults: {
ignoredFolders: "Trash,node_modules,Library",
ignoreDotFolders: "true",
addNewlineToCopy: "true"
}
});

module.exports = {
get ignoredFolders() {
return config.get("ignoredFolders", "Trash,Library,node_modules").split(",").filter(item => item !== "").filter((v, i, a) => a.indexOf(v) === i);
},
set ignoredFolders(folders) {
config.set("ignoredFolders", folders.split(",").filter(item => item !== "").filter((value, index, self) => self.indexOf(value) === index).join())
},

get ignoreDotFolders() {
return fromBool(config.get("ignoreDotFolders", "true"));
},
set ignoreDotFolders(ignore) {
config.set("ignoreDotFolders", toBool(ignore));
},

get addNewlineToCopy() {
return fromBool(config.get("addNewlineToCopy", "true"));
},
set addNewlineToCopy(add) {
config.set("addNewlineToCopy", toBool(add))
},

path: config.path,

reset(...keys) {
config.reset(...keys);
},

clear() {
config.clear();
}
}

const fromBool = str => str === "true";
const toBool = str => {
if (str == null) return "false";

if (typeof str === "boolean") return str.toString();

if (typeof str === "string") {
if (str == "") return "false";

str = str.replace(/^\s+|\s+$/g, "");
if (str.toLowerCase() == "true" || str.toLowerCase() == "yes") return "true";

str = str.replace(/,/g, ".");
str = str.replace(/^\s*\-\s*/g, "-");
}

if (!isNaN(str)) return (parseFloat(str) != 0).toString();

return "false";
}
Loading

0 comments on commit 80e54be

Please sign in to comment.