Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit 61b118f

Browse files
committed
fix(packages/core): backslashes not always properly parsed
Fixes #5287
1 parent d1aa46d commit 61b118f

File tree

4 files changed

+61
-23
lines changed

4 files changed

+61
-23
lines changed

packages/core/src/repl/split.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ export interface Split {
4646
endIndices: number[]
4747
}
4848

49+
const endsWithQuoteSpace = (str: string, idx: number, lookFor: string): boolean => {
50+
for (let ii = idx + 1; ii < str.length; ii++) {
51+
if (str.charAt(ii) === lookFor) {
52+
return ii === str.length - 1 || /\s/.test(str.charAt(ii + 1))
53+
}
54+
}
55+
56+
return false
57+
}
58+
4959
export const _split = (
5060
str: string,
5161
removeOuterQuotes = true,
@@ -58,31 +68,21 @@ export const _split = (
5868

5969
let cur = ''
6070

61-
const endsWithQuoteSpace = (idx: number, lookFor: string): boolean => {
62-
for (let ii = idx + 1; ii < str.length; ii++) {
63-
if (str.charAt(ii) === lookFor) {
64-
return ii === str.length - 1 || /\s/.test(str.charAt(ii + 1))
65-
}
66-
}
67-
68-
return false
69-
}
70-
7171
const removedLastOpenQuote: boolean[] = []
7272
let escapeActive = false
7373
for (let idx = 0; idx < str.length; idx++) {
74-
const char = str.charAt(idx)
74+
let char = str.charAt(idx)
7575

7676
if (char === '\\') {
7777
if (!escapeActive) {
7878
escapeActive = true
79+
char = str.charAt(++idx)
7980
} else {
8081
escapeActive = false
8182
cur += '\\'
83+
continue
8284
}
83-
84-
continue
85-
} else if (!escapeActive) {
85+
} else if (escapeActive) {
8686
escapeActive = false
8787
}
8888

@@ -117,7 +117,7 @@ export const _split = (
117117
// found open quote
118118
const removeQuote =
119119
removeOuterQuotes &&
120-
endsWithQuoteSpace(idx, char) &&
120+
endsWithQuoteSpace(str, idx, char) &&
121121
(idx === 0 ||
122122
(stack.length === 0 && (removeInlineOuterQuotes || patterns.whitespace.test(str.charAt(idx - 1)))))
123123

plugins/plugin-core-support/src/lib/cmds/echo.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,11 @@
1414
* limitations under the License.
1515
*/
1616

17-
//
18-
// Note: for now, this is disabled in favor of the bash-like shell
19-
// echo; we should probably restore for support for browser/no-proxy
20-
// mode.
21-
//
17+
import { Registrar } from '@kui-shell/core'
2218

23-
export default () => {
24-
/* commandTree.listen('/echo', ({ argvNoOptions }) => {
19+
/** For debugging the command line parser */
20+
export default (registrar: Registrar) => {
21+
registrar.listen('/kuiecho', ({ argvNoOptions }) => {
2522
return argvNoOptions.slice(1).join(' ') || true
26-
}) */
23+
})
2724
}

plugins/plugin-core-support/src/plugin.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import { isHeadless, Registrar } from '@kui-shell/core'
1818

1919
// import help from './lib/cmds/help'
20+
import echo from './lib/cmds/echo'
2021
import quit from './lib/cmds/quit'
2122
import clear from './lib/cmds/clear'
2223
import base64 from './lib/cmds/base64'
@@ -34,6 +35,7 @@ import tabManagement from './lib/cmds/tab-management'
3435
export default async (commandTree: Registrar) => {
3536
await Promise.all([
3637
// help(commandTree, options),
38+
echo(commandTree),
3739
quit(commandTree),
3840
clear(commandTree),
3941
base64(commandTree),
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2020 IBM Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Test command line parsing
19+
*
20+
*/
21+
import { Common, CLI, ReplExpect } from '@kui-shell/test'
22+
23+
const input1 = 'hi ho\\\\.mo\\.zo \\ff'
24+
const output1 = 'hi ho\\.mo.zo ff'
25+
26+
describe(`Command line parsing ${process.env.MOCHA_RUN_TARGET || ''}`, function(this: Common.ISuite) {
27+
before(Common.before(this))
28+
after(Common.after(this))
29+
30+
it('should properly handle backslash escapes with pty commands', () =>
31+
CLI.command(`echo ${input1}`, this.app)
32+
.then(ReplExpect.okWithPtyOutput(output1))
33+
.catch(Common.oops(this, true)))
34+
35+
it('should properly handle backslash escapes with kui commands', () =>
36+
CLI.command(`kuiecho ${input1}`, this.app)
37+
.then(ReplExpect.okWithString(output1))
38+
.catch(Common.oops(this, true)))
39+
})

0 commit comments

Comments
 (0)