From 79f4cdd25cc106519bfb1e46a3daa78fc2ae15fd Mon Sep 17 00:00:00 2001 From: "zokutyou2@gmail.com" Date: Wed, 14 Jul 2021 21:35:44 +0900 Subject: [PATCH] display help, description and add tab autocompletion --- mitmproxy/tools/web/app.py | 10 ++- .../Command/__snapshots__/CommandSpec.js.snap | 5 ++ web/src/js/components/CommandBar.tsx | 62 +++++++++++++------ 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/mitmproxy/tools/web/app.py b/mitmproxy/tools/web/app.py index e57a7b682..0bf0f1d51 100644 --- a/mitmproxy/tools/web/app.py +++ b/mitmproxy/tools/web/app.py @@ -455,10 +455,14 @@ class Commands(RequestHandler): def get(self): commands = {} for (name, command) in self.master.commands.commands.items(): - commands[name] = [] + commands[name] = { + "args": [], + "signature_help": command.signature_help(), + "description": command.help + } for parameter in command.parameters: - commands[name].append({"name": parameter.name}) - self.write({"commands": commands}) + commands[name]["args"].append(parameter.name) + self.write({"commands": commands, "history": self.master.commands.execute("commands.history.get")}) def post(self): result = self.master.commands.execute(self.json["command"]) diff --git a/web/src/js/__tests__/components/Command/__snapshots__/CommandSpec.js.snap b/web/src/js/__tests__/components/Command/__snapshots__/CommandSpec.js.snap index f9bb32b65..5719df613 100644 --- a/web/src/js/__tests__/components/Command/__snapshots__/CommandSpec.js.snap +++ b/web/src/js/__tests__/components/Command/__snapshots__/CommandSpec.js.snap @@ -30,6 +30,11 @@ exports[`CommandBar Component 1`] = ` value="" /> +
+ Available Commands: [] +
`; diff --git a/web/src/js/components/CommandBar.tsx b/web/src/js/components/CommandBar.tsx index 70a0fda41..2508c42f3 100644 --- a/web/src/js/components/CommandBar.tsx +++ b/web/src/js/components/CommandBar.tsx @@ -3,7 +3,7 @@ import classnames from 'classnames' import { Key, fetchApi } from '../utils' import Filt from '../filt/command' -export function AvailableCommands({input, commands}) { +function getAvailableCommands(commands, input = "") { if (!commands) return null let availableCommands = [] for (const [command, args] of Object.entries(commands)) { @@ -11,10 +11,10 @@ export function AvailableCommands({input, commands}) { availableCommands.push(command) } } - return
Available Commands: {JSON.stringify(availableCommands)}
+ return availableCommands } -export function ArgumentSuggestion({nextArgs, currentArg}){ +export function CommandHelp({nextArgs, currentArg, help, description}){ let results = [] for (let i = 0; i < nextArgs.length; i++) { if (i==currentArg) { @@ -26,37 +26,49 @@ export function ArgumentSuggestion({nextArgs, currentArg}){ return (
- Argument suggestion: {results} +
Argument suggestion: {results}
+ { help.includes("->") &&
Signature help: {help}
} + { description &&
# {description}
}
) } export default function CommandBar() { const [input, setInput] = useState("") - const [command, setCommand] = useState("") - const [results, setResults] = useState([]) - const [history, setHistory] = useState([]) - const [currentPos, setCurrentPos] = useState(0) + const [originalInput, setOriginalInput] = useState("") + const [currentCompletion, setCurrentCompletion] = useState(0) + + const [availableCommands, setAvailableCommands] = useState([]) const [allCommands, setAllCommands] = useState({}) const [nextArgs, setNextArgs] = useState([]) const [currentArg, setCurrentArg] = useState(0) - const [commandHelp, setCommandHelp] = useState("") + const [signatureHelp, setSignatureHelp] = useState("") + const [description, setDescription] = useState("") + + const [results, setResults] = useState([]) + const [history, setHistory] = useState([]) + const [currentPos, setCurrentPos] = useState(0) useEffect(() => { fetchApi('/commands', { method: 'GET' }) .then(response => response.json()) - .then(data => setAllCommands(data)) + .then(data => { + setAllCommands(data) + setAvailableCommands(getAvailableCommands(data["commands"])) + }) }, []) - const parseCommand = (input) => { + const parseCommand = (originalInput, input) => { const parts = Filt.parse(input) - if (allCommands["commands"].hasOwnProperty(parts[0])){ - setCommand(parts[0]) - } else { - setCommand("") - } + const originalParts = Filt.parse(originalInput) + const commands = allCommands["commands"] - const nextArgs = allCommands["commands"][parts[0]]?.map(arg => arg.name) + setSignatureHelp(commands[parts[0]]?.signature_help) + setDescription(commands[parts[0]]?.description) + + setAvailableCommands(getAvailableCommands(commands, originalParts[0])) + + const nextArgs = allCommands["commands"][parts[0]]?.args if (nextArgs) { setNextArgs([parts[0], ...nextArgs]) @@ -66,6 +78,7 @@ export default function CommandBar() { const onChange = (e) => { setInput(e.target.value) + setOriginalInput(e.target.value) } const onKeyDown = (e) => { @@ -91,25 +104,34 @@ export default function CommandBar() { }) setInput("") + setOriginalInput("") } if (e.keyCode === Key.UP) { if (currentPos > 0) { setInput(history[currentPos - 1]) + setOriginalInput(history[currentPos -1]) setCurrentPos(currentPos - 1) } } if (e.keyCode === Key.DOWN) { setInput(history[currentPos]) + setOriginalInput(history[currentPos]) if (currentPos < history.length -1) { setCurrentPos(currentPos + 1) } } + if (e.keyCode === Key.TAB) { + setInput(availableCommands[currentCompletion]) + setCurrentCompletion((currentCompletion + 1) % availableCommands.length) + e.preventDefault() + } e.stopPropagation() } const onKeyUp = (e) => { if (input == "") return - parseCommand(input) + console.log("keyup event") + parseCommand(originalInput, input) e.stopPropagation() } @@ -125,7 +147,7 @@ export default function CommandBar() {
))} - { nextArgs.length > 0 && } + { signatureHelp && }
@@ -140,7 +162,7 @@ export default function CommandBar() { onKeyUp={onKeyUp} />
- { !command && } +
Available Commands: {JSON.stringify(availableCommands)}
) } \ No newline at end of file