mirror of
https://github.com/gechandesu/shellish.git
synced 2026-10-05 00:46:47 +03:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a34efe4e4e | ||
|
|
917b47c94a |
@@ -0,0 +1,48 @@
|
||||
name: Docs
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup V
|
||||
run: |
|
||||
wget -qO /tmp/v.zip https://github.com/vlang/v/releases/latest/download/v_linux.zip
|
||||
unzip -q /tmp/v.zip -d /tmp
|
||||
echo /tmp/v >> "$GITHUB_PATH"
|
||||
|
||||
- name: Build docs
|
||||
run: |
|
||||
v doc -f html -m .
|
||||
pushd _docs
|
||||
ln -vs ${{ github.event.repository.name }}.html index.html
|
||||
ls -alFh
|
||||
popd
|
||||
|
||||
- name: Upload static files as artifact
|
||||
id: deployment
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: _docs/
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
@@ -0,0 +1,27 @@
|
||||
name: Lint and test
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup V
|
||||
run: |
|
||||
wget -qO /tmp/v.zip https://github.com/vlang/v/releases/latest/download/v_linux.zip
|
||||
unzip -q /tmp/v.zip -d /tmp
|
||||
echo /tmp/v >> "$GITHUB_PATH"
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
v fmt -verify .
|
||||
v vet -v -W -I -F -r .
|
||||
v missdoc -r --verify .
|
||||
v -stats test .
|
||||
+48
-9
@@ -8,7 +8,7 @@ pub const safe_chars = '%+,-./0123456789:=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghij
|
||||
// special_chars contains ASCII characters that must be escaped in shell.
|
||||
pub const special_chars = ' \$"\'\\!'
|
||||
|
||||
const special_chars_runes = [` `, `$`, `"`, `'`, `\``, `\\`, `!`]
|
||||
const special_chars_runes = [` `, `$`, `"`, `'`, `\``, `\\`, `!`]!
|
||||
|
||||
// quote returns a quoted version of string `s`.
|
||||
//
|
||||
@@ -163,12 +163,14 @@ fn parse(line string) ![]string {
|
||||
mut single_quoted := false
|
||||
mut double_quoted := false
|
||||
mut back_quoted := false
|
||||
mut dollar_quoted := false
|
||||
mut dollar_depth := 0
|
||||
mut commented := false
|
||||
|
||||
mut got := Mode.no
|
||||
|
||||
for i, c in line {
|
||||
mut r := c
|
||||
dollar_quoted := dollar_depth > 0
|
||||
|
||||
if escaped {
|
||||
if r == `t` {
|
||||
@@ -177,8 +179,14 @@ fn parse(line string) ![]string {
|
||||
if r == `n` {
|
||||
r = `\n`
|
||||
}
|
||||
buf << r
|
||||
escaped = false
|
||||
if commented {
|
||||
if r == `\n` {
|
||||
commented = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
buf << r
|
||||
got = .normal
|
||||
continue
|
||||
}
|
||||
@@ -199,6 +207,36 @@ fn parse(line string) ![]string {
|
||||
continue
|
||||
}
|
||||
|
||||
if commented {
|
||||
if r == `\n` {
|
||||
commented = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if r == `#` && !single_quoted && !double_quoted && !back_quoted && !dollar_quoted {
|
||||
// Everything up to the end of the line is a comment. The word being
|
||||
// accumulated, if any, is terminated by it.
|
||||
if got != .no {
|
||||
tokens << buf.bytestr()
|
||||
buf = []u8{}
|
||||
got = .no
|
||||
}
|
||||
commented = true
|
||||
continue
|
||||
}
|
||||
|
||||
if r == `;` && !single_quoted && !double_quoted && !back_quoted && !dollar_quoted {
|
||||
// Command separator is a token on its own.
|
||||
if got != .no {
|
||||
tokens << buf.bytestr()
|
||||
buf = []u8{}
|
||||
}
|
||||
tokens << ';'
|
||||
got = .no
|
||||
continue
|
||||
}
|
||||
|
||||
if r.is_space() {
|
||||
if single_quoted || double_quoted || back_quoted || dollar_quoted {
|
||||
buf << r
|
||||
@@ -217,17 +255,18 @@ fn parse(line string) ![]string {
|
||||
}
|
||||
}
|
||||
`(` {
|
||||
if !single_quoted && !double_quoted && !dollar_quoted {
|
||||
if !dollar_quoted && buf.len - 1 >= 0 && buf[buf.len - 1..][0] == `$` {
|
||||
dollar_quoted = true
|
||||
if !single_quoted && !double_quoted {
|
||||
// Opens a `$(` expression or nests inside an already opened one.
|
||||
if dollar_quoted || (buf.len > 0 && buf.last() == `$`) {
|
||||
dollar_depth++
|
||||
buf << r
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
`)` {
|
||||
if !single_quoted && !double_quoted && !dollar_quoted {
|
||||
dollar_quoted = false
|
||||
if !single_quoted && !double_quoted && dollar_quoted {
|
||||
dollar_depth--
|
||||
}
|
||||
}
|
||||
`"` {
|
||||
@@ -264,7 +303,7 @@ fn parse(line string) ![]string {
|
||||
single_quoted { return error('non-terminated quote in string') }
|
||||
double_quoted { return error('non-terminated double quote in string') }
|
||||
back_quoted { return error('non-terminated backtick in string') }
|
||||
dollar_quoted { return error('non-terminated dollar expression in string') }
|
||||
dollar_depth > 0 { return error('non-terminated dollar expression in string') }
|
||||
else {}
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -30,7 +30,6 @@ fn test_strip_ansi_escape_codes() {
|
||||
}
|
||||
|
||||
// Original test data taken from https://github.com/python/cpython/blob/3.14/Lib/test/test_shlex.py
|
||||
// FIXME: All test-cases must pass.
|
||||
// vfmt off
|
||||
const test_data = {
|
||||
'foo': ['foo']
|
||||
@@ -90,10 +89,10 @@ const test_data = {
|
||||
'":-) ;-)"': [':-) ;-)']
|
||||
'foo `bar baz`': ['foo', '`bar baz`']
|
||||
r'foo "$(bar baz)"': ['foo', r'$(bar baz)']
|
||||
// r'foo $(bar)': ['foo', r'$(bar)'] // failing
|
||||
// r'foo $(bar baz)': ['foo', r'$(bar baz)'] // failing
|
||||
// r'foo#bar\nbaz': ['foo', 'baz'] // failing
|
||||
// 'foo;bar': ['foo', ';', 'bar'] // failing
|
||||
r'foo $(bar)': ['foo', r'$(bar)']
|
||||
r'foo $(bar baz)': ['foo', r'$(bar baz)']
|
||||
r'foo#bar\nbaz': ['foo', 'baz']
|
||||
'foo;bar': ['foo', ';', 'bar']
|
||||
|
||||
'"foo\\\\\\x bar\\" df\'a\\ \'df"': ['foo\\\\x bar" df\'a\\ \'df']
|
||||
'"foo\\ x\\x\\\\"\\\'"foobar"': [r"foo\ x\x\'foobar"]
|
||||
|
||||
Reference in New Issue
Block a user