-
-
Notifications
You must be signed in to change notification settings - Fork 76
feat: add completion command #442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 5 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
92ff222
feat: add completion command
Zamoca42 54e853b
update: completion from command to option and update help messages
Zamoca42 39ce69d
Merge branch 'main' into feat/completion
Zamoca42 f775586
test: Use cross-platform paths in completion tests
Zamoca42 cb87c07
style: Change completion option argument from <shell> to [shell] for …
Zamoca42 5dc0ed1
docs: update README.md
Zamoca42 985fad3
docs: update README.md for oh-my-zsh users
Zamoca42 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
'use strict'; | ||
|
||
const fs = require('fs'); | ||
const path = require('path'); | ||
const os = require('os'); | ||
const { UnsupportedShellError, CompletionScriptError } = require('./errors'); | ||
|
||
class Completion { | ||
constructor(shell) { | ||
this.supportedShells = ['bash', 'zsh']; | ||
if (!this.supportedShells.includes(shell)) { | ||
throw new UnsupportedShellError(shell, this.supportedShells); | ||
} | ||
this.shell = shell; | ||
this.rcFilename = shell === 'zsh' ? '.zshrc' : '.bashrc'; | ||
} | ||
|
||
getFilePath() { | ||
const homeDir = os.homedir(); | ||
return path.join(homeDir, this.rcFilename); | ||
} | ||
|
||
appendScript(script) { | ||
const rcFilePath = this.getFilePath(); | ||
return new Promise((resolve, reject) => { | ||
fs.appendFile(rcFilePath, `\n${script}\n`, (err) => { | ||
if (err) { | ||
reject((new CompletionScriptError(`Error appending to ${rcFilePath}: ${err.message}`))); | ||
} else { | ||
console.log(`Completion script added to ${rcFilePath}`); | ||
console.log(`Please restart your shell or run 'source ~/${this.rcFilename}' to enable completions`); | ||
resolve(); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
getScript() { | ||
return new Promise((resolve) => { | ||
if (this.shell === 'zsh') { | ||
resolve(this.getZshScript()); | ||
} else if (this.shell === 'bash') { | ||
resolve(this.getBashScript()); | ||
} | ||
}); | ||
} | ||
|
||
getZshScript() { | ||
const completionDir = path.join(__dirname, '..', 'bin', 'completion', 'zsh'); | ||
return ` | ||
# tldr zsh completion | ||
fpath=(${completionDir} $fpath) | ||
# You might need to force rebuild zcompdump: | ||
# rm -f ~/.zcompdump; compinit | ||
# If you're using oh-my-zsh, you can force reload of completions: | ||
# autoload -U compinit && compinit | ||
# Check if compinit is already loaded, if not, load it | ||
if (( ! $+functions[compinit] )); then | ||
autoload -Uz compinit | ||
compinit -C | ||
fi | ||
`.trim(); | ||
} | ||
|
||
getBashScript() { | ||
return new Promise((resolve, reject) => { | ||
const scriptPath = path.join(__dirname, '..', 'bin', 'completion', 'bash', 'tldr'); | ||
fs.readFile(scriptPath, 'utf8', (err, data) => { | ||
if (err) { | ||
reject(new CompletionScriptError(`Error reading bash completion script: ${err.message}`)); | ||
} else { | ||
resolve(data); | ||
} | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
module.exports = Completion; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
'use strict'; | ||
|
||
const Completion = require('../lib/completion'); | ||
const { UnsupportedShellError, CompletionScriptError } = require('../lib/errors'); | ||
const sinon = require('sinon'); | ||
const fs = require('fs'); | ||
const os = require('os'); | ||
const should = require('should'); | ||
const path = require('path'); | ||
|
||
describe('Completion', () => { | ||
const zshrcPath = path.join(os.homedir(), '.zshrc'); | ||
const bashrcPath = path.join(os.homedir(), '.bashrc'); | ||
|
||
describe('constructor()', () => { | ||
it('should construct with supported shell', () => { | ||
const completion = new Completion('zsh'); | ||
should.exist(completion); | ||
completion.shell.should.equal('zsh'); | ||
completion.rcFilename.should.equal('.zshrc'); | ||
}); | ||
|
||
it('should throw UnsupportedShellError for unsupported shell', () => { | ||
(() => {return new Completion('fish');}).should.throw(UnsupportedShellError); | ||
}); | ||
}); | ||
|
||
describe('getFilePath()', () => { | ||
it('should return .zshrc path for zsh', () => { | ||
const completion = new Completion('zsh'); | ||
completion.getFilePath().should.equal(zshrcPath); | ||
}); | ||
|
||
it('should return .bashrc path for bash', () => { | ||
const completion = new Completion('bash'); | ||
completion.getFilePath().should.equal(bashrcPath); | ||
}); | ||
}); | ||
|
||
describe('appendScript()', () => { | ||
let appendFileStub; | ||
|
||
beforeEach(() => { | ||
appendFileStub = sinon.stub(fs, 'appendFile').yields(null); | ||
}); | ||
|
||
afterEach(() => { | ||
appendFileStub.restore(); | ||
}); | ||
|
||
it('should append script to file', () => { | ||
const completion = new Completion('zsh'); | ||
return completion.appendScript('test script') | ||
.then(() => { | ||
appendFileStub.calledOnce.should.be.true(); | ||
appendFileStub.firstCall.args[0].should.equal(zshrcPath); | ||
appendFileStub.firstCall.args[1].should.equal('\ntest script\n'); | ||
}); | ||
}); | ||
|
||
it('should reject with CompletionScriptError on fs error', () => { | ||
const completion = new Completion('zsh'); | ||
appendFileStub.yields(new Error('File write error')); | ||
return completion.appendScript('test script') | ||
.should.be.rejectedWith(CompletionScriptError); | ||
}); | ||
}); | ||
|
||
describe('getScript()', () => { | ||
it('should return zsh script for zsh shell', () => { | ||
const completion = new Completion('zsh'); | ||
return completion.getScript() | ||
.then((script) => { | ||
script.should.containEql('# tldr zsh completion'); | ||
script.should.containEql('fpath=('); | ||
}); | ||
}); | ||
|
||
it('should return bash script for bash shell', () => { | ||
const completion = new Completion('bash'); | ||
const readFileStub = sinon.stub(fs, 'readFile').yields(null, '# bash completion script'); | ||
|
||
return completion.getScript() | ||
.then((script) => { | ||
script.should.equal('# bash completion script'); | ||
readFileStub.restore(); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('getZshScript()', () => { | ||
it('should return zsh completion script', () => { | ||
const completion = new Completion('zsh'); | ||
const script = completion.getZshScript(); | ||
script.should.containEql('# tldr zsh completion'); | ||
script.should.containEql('fpath=('); | ||
script.should.containEql('compinit'); | ||
}); | ||
}); | ||
|
||
describe('getBashScript()', () => { | ||
let readFileStub; | ||
|
||
beforeEach(() => { | ||
readFileStub = sinon.stub(fs, 'readFile'); | ||
}); | ||
|
||
afterEach(() => { | ||
readFileStub.restore(); | ||
}); | ||
|
||
it('should return bash completion script', () => { | ||
const completion = new Completion('bash'); | ||
readFileStub.yields(null, '# bash completion script'); | ||
|
||
return completion.getBashScript() | ||
.then((script) => { | ||
script.should.equal('# bash completion script'); | ||
}); | ||
}); | ||
|
||
it('should reject with CompletionScriptError on fs error', () => { | ||
const completion = new Completion('bash'); | ||
readFileStub.yields(new Error('File read error')); | ||
|
||
return completion.getBashScript() | ||
.should.be.rejectedWith(CompletionScriptError); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.