mirror of
https://github.com/betaflight/betaflight-configurator.git
synced 2025-07-25 17:25:16 +03:00
Fix cli cleanup exit command after auto completing
This commit is contained in:
parent
2e5bdae80e
commit
6fd0153b91
2 changed files with 63 additions and 54 deletions
|
@ -11,6 +11,36 @@ function removePromptHash(promptText) {
|
||||||
return promptText.replace(/^# /, '');
|
return promptText.replace(/^# /, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cliBufferCharsToDelete(command, buffer) {
|
||||||
|
var commonChars = 0;
|
||||||
|
for (var i = 0;i < buffer.length;i++) {
|
||||||
|
if (command[i] === buffer[i]) {
|
||||||
|
commonChars++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.length - commonChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
function commandWithBackSpaces(command, buffer, noOfCharsToDelete) {
|
||||||
|
const backspace = String.fromCharCode(127);
|
||||||
|
return backspace.repeat(noOfCharsToDelete) + command.substring(buffer.length - noOfCharsToDelete, command.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCliCommand(command, cliBuffer) {
|
||||||
|
const buffer = removePromptHash(cliBuffer);
|
||||||
|
const bufferRegex = new RegExp('^' + buffer, 'g');
|
||||||
|
if (command.match(bufferRegex)) {
|
||||||
|
return command.replace(bufferRegex, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
const noOfCharsToDelete = cliBufferCharsToDelete(command, buffer);
|
||||||
|
|
||||||
|
return commandWithBackSpaces(command, buffer, noOfCharsToDelete);
|
||||||
|
}
|
||||||
|
|
||||||
TABS.cli.initialize = function (callback) {
|
TABS.cli.initialize = function (callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
@ -61,7 +91,7 @@ TABS.cli.initialize = function (callback) {
|
||||||
writer.write(new Blob([self.outputHistory], {type: 'text/plain'}));
|
writer.write(new Blob([self.outputHistory], {type: 'text/plain'}));
|
||||||
} else {
|
} else {
|
||||||
console.log('write complete');
|
console.log('write complete');
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
writer.truncate(0);
|
writer.truncate(0);
|
||||||
|
@ -71,36 +101,6 @@ TABS.cli.initialize = function (callback) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function cliBufferCharsToDelete(command, buffer) {
|
|
||||||
var commonChars = 0;
|
|
||||||
for (var i = 0;i < buffer.length;i++) {
|
|
||||||
if (command[i] === buffer[i]) {
|
|
||||||
commonChars++;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer.length - commonChars;
|
|
||||||
}
|
|
||||||
|
|
||||||
function commandWithBackSpaces(command, buffer, noOfCharsToDelete) {
|
|
||||||
const backspace = String.fromCharCode(127);
|
|
||||||
return backspace.repeat(noOfCharsToDelete) + command.substring(buffer.length - noOfCharsToDelete, command.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCliCommand(command, cliBuffer) {
|
|
||||||
const buffer = removePromptHash(cliBuffer);
|
|
||||||
const bufferRegex = new RegExp('^' + buffer, 'g');
|
|
||||||
if (command.match(bufferRegex)) {
|
|
||||||
return command.replace(bufferRegex, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
const noOfCharsToDelete = cliBufferCharsToDelete(command, buffer);
|
|
||||||
|
|
||||||
return commandWithBackSpaces(command, buffer, noOfCharsToDelete);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tab key detection must be on keydown,
|
// Tab key detection must be on keydown,
|
||||||
// `keypress`/`keyup` happens too late, as `textarea` will have already lost focus.
|
// `keypress`/`keyup` happens too late, as `textarea` will have already lost focus.
|
||||||
textarea.keydown(function (event) {
|
textarea.keydown(function (event) {
|
||||||
|
@ -134,7 +134,7 @@ TABS.cli.initialize = function (callback) {
|
||||||
if (line.toLowerCase().startsWith('profile')) {
|
if (line.toLowerCase().startsWith('profile')) {
|
||||||
processingDelay = self.profileSwitchDelayMs;
|
processingDelay = self.profileSwitchDelayMs;
|
||||||
}
|
}
|
||||||
const isLastCommand = index + 1 === outputArray.length;
|
const isLastCommand = outputArray.length === index + 1;
|
||||||
if (isLastCommand && self.cliBuffer) {
|
if (isLastCommand && self.cliBuffer) {
|
||||||
line = getCliCommand(line, self.cliBuffer);
|
line = getCliCommand(line, self.cliBuffer);
|
||||||
}
|
}
|
||||||
|
@ -317,11 +317,11 @@ TABS.cli.read = function (readInfo) {
|
||||||
};
|
};
|
||||||
|
|
||||||
TABS.cli.sendLine = function (line, callback) {
|
TABS.cli.sendLine = function (line, callback) {
|
||||||
TABS.cli.send(line + '\n', callback);
|
this.send(line + '\n', callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
TABS.cli.sendAutoComplete = function (line, callback) {
|
TABS.cli.sendAutoComplete = function (line, callback) {
|
||||||
TABS.cli.send(line + '\t', callback);
|
this.send(line + '\t', callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
TABS.cli.send = function (line, callback) {
|
TABS.cli.send = function (line, callback) {
|
||||||
|
@ -340,17 +340,7 @@ TABS.cli.cleanup = function (callback) {
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.send(getCliCommand('exit\r', this.cliBuffer), function (writeInfo) {
|
||||||
var bufferOut = new ArrayBuffer(5);
|
|
||||||
var bufView = new Uint8Array(bufferOut);
|
|
||||||
|
|
||||||
bufView[0] = 0x65; // e
|
|
||||||
bufView[1] = 0x78; // x
|
|
||||||
bufView[2] = 0x69; // i
|
|
||||||
bufView[3] = 0x74; // t
|
|
||||||
bufView[4] = 0x0D; // enter
|
|
||||||
|
|
||||||
serial.send(bufferOut, function (writeInfo) {
|
|
||||||
// we could handle this "nicely", but this will do for now
|
// we could handle this "nicely", but this will do for now
|
||||||
// (another approach is however much more complicated):
|
// (another approach is however much more complicated):
|
||||||
// we can setup an interval asking for data lets say every 200ms, when data arrives, callback will be triggered and tab switched
|
// we can setup an interval asking for data lets say every 200ms, when data arrives, callback will be triggered and tab switched
|
||||||
|
|
|
@ -35,14 +35,17 @@ describe('TABS.cli', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ambiguous auto-complete results', () => {
|
it('ambiguous auto-complete results', () => {
|
||||||
|
TABS.cli.cliBuffer = 'se';
|
||||||
|
|
||||||
TABS.cli.read({
|
TABS.cli.read({
|
||||||
data: toArrayBuffer('\r\033[Kserialpassthrough\tservo\r\n# ser')
|
data: toArrayBuffer('\r\033[Kserialpassthrough\tservo\r\n# ser')
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ambigous auto-complete from firmware is preceded with an \r carriage return
|
// Ambigous auto-complete from firmware is preceded with an \r carriage return
|
||||||
|
// which only renders a line break on Mac
|
||||||
const expectedValue = GUI.operating_system === "MacOS" ?
|
const expectedValue = GUI.operating_system === "MacOS" ?
|
||||||
'<br>serialpassthrough\tservo<br>' :
|
'se<br>serialpassthrough\tservo<br>' :
|
||||||
'serialpassthrough\tservo<br>';
|
'seserialpassthrough\tservo<br>';
|
||||||
expect(cliOutput.html()).to.equal(expectedValue);
|
expect(cliOutput.html()).to.equal(expectedValue);
|
||||||
expect(cliPrompt.val()).to.equal('ser');
|
expect(cliPrompt.val()).to.equal('ser');
|
||||||
});
|
});
|
||||||
|
@ -91,6 +94,8 @@ describe('TABS.cli', () => {
|
||||||
input.trigger(event);
|
input.trigger(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const backspaceCode = String.fromCharCode(127);
|
||||||
|
|
||||||
describe('input', () => {
|
describe('input', () => {
|
||||||
const content = $('<div>').attr('id', 'content');
|
const content = $('<div>').attr('id', 'content');
|
||||||
const cliTab = $('<div>').addClass('tab-cli');
|
const cliTab = $('<div>').addClass('tab-cli');
|
||||||
|
@ -181,10 +186,8 @@ describe('TABS.cli', () => {
|
||||||
|
|
||||||
triggerTabKey(cliPrompt);
|
triggerTabKey(cliPrompt);
|
||||||
|
|
||||||
const backspace = String.fromCharCode(127);
|
|
||||||
|
|
||||||
expect(TABS.cli.send).to.have.been.calledOnce;
|
expect(TABS.cli.send).to.have.been.calledOnce;
|
||||||
expect(TABS.cli.send).to.have.been.calledWith(backspace.repeat(3) + '\t');
|
expect(TABS.cli.send).to.have.been.calledWith(backspaceCode.repeat(3) + '\t');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -225,15 +228,13 @@ describe('TABS.cli', () => {
|
||||||
|
|
||||||
triggerEnterKey(cliPrompt);
|
triggerEnterKey(cliPrompt);
|
||||||
|
|
||||||
const backspace = String.fromCharCode(127);
|
|
||||||
|
|
||||||
expect(TABS.cli.send).to.have.been.calledOnce;
|
expect(TABS.cli.send).to.have.been.calledOnce;
|
||||||
expect(TABS.cli.send).to.have.been.calledWith(backspace.repeat(3) + '\n');
|
expect(TABS.cli.send).to.have.been.calledWith(backspaceCode.repeat(3) + '\n');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cliBufer is cleared on startup', done => {
|
it('cliBuffer is cleared on startup', done => {
|
||||||
TABS.cli.cliBuffer = '# serial';
|
TABS.cli.cliBuffer = '# serial';
|
||||||
|
|
||||||
TABS.cli.initialize(() => {
|
TABS.cli.initialize(() => {
|
||||||
|
@ -241,5 +242,23 @@ describe('TABS.cli', () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('exit upon cleanup clears cliBuffer first', done => {
|
||||||
|
CONFIGURATOR.connectionValid = true;
|
||||||
|
TABS.cli.cliValid = true;
|
||||||
|
|
||||||
|
|
||||||
|
TABS.cli.initialize(() => {
|
||||||
|
const commandInBuffer = 'resource';
|
||||||
|
|
||||||
|
TABS.cli.cliBuffer = `# ${commandInBuffer}`;
|
||||||
|
|
||||||
|
TABS.cli.cleanup();
|
||||||
|
|
||||||
|
expect(TABS.cli.send).to.have.been.calledOnce;
|
||||||
|
expect(TABS.cli.send).to.have.been.calledWith(backspaceCode.repeat(commandInBuffer.length) + 'exit\r');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue