mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
vlib: add encoding.txtar
(port of Go's txtar module) (#20874)
This commit is contained in:
parent
efa98d9234
commit
c60a869fb4
4 changed files with 320 additions and 0 deletions
94
vlib/encoding/txtar/txtar.v
Normal file
94
vlib/encoding/txtar/txtar.v
Normal file
|
@ -0,0 +1,94 @@
|
|||
module txtar
|
||||
|
||||
// Ported from https://cs.opensource.google/go/x/tools/+/master:txtar/archive.go
|
||||
import strings
|
||||
|
||||
// Archive is a collection of files
|
||||
pub struct Archive {
|
||||
pub mut:
|
||||
comment string // the start of the archive; contains potentially multiple lines, before the files
|
||||
files []File // a series of files
|
||||
}
|
||||
|
||||
// File is a single file in an Archive. Each starting with a `-- FILENAME --` line.
|
||||
pub struct File {
|
||||
pub mut:
|
||||
path string // 'abc/def.v' from the `-- abc/def.v --` header
|
||||
content string // everything after that, till the next `-- name --` line.
|
||||
}
|
||||
|
||||
// str returns a string representation of the `a` Archive.
|
||||
// It is suitable for storing in a text file.
|
||||
// It is also in the same format, that txtar.parse/1 expects.
|
||||
pub fn (a &Archive) str() string {
|
||||
mut sb := strings.new_builder(a.comment.len + 200 * a.files.len)
|
||||
sb.write_string(fix_nl(a.comment))
|
||||
for f in a.files {
|
||||
sb.write_string('-- ${f.path} --\n')
|
||||
sb.write_string(fix_nl(f.content))
|
||||
}
|
||||
return sb.str()
|
||||
}
|
||||
|
||||
// parse parses the serialized form of an Archive.
|
||||
// The returned Archive holds slices of data.
|
||||
pub fn parse(content string) Archive {
|
||||
mut a := Archive{}
|
||||
comment, mut name, mut data := find_file_marker(content)
|
||||
a.comment = comment
|
||||
for name != '' {
|
||||
mut f := File{name, ''}
|
||||
f.content, name, data = find_file_marker(data)
|
||||
a.files << f
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
const nlm = '\n-- '
|
||||
const mstart = '-- '
|
||||
const mend = ' --'
|
||||
|
||||
// find_file_marker finds the next file marker in data, extracts the file name,
|
||||
// and returns the data before the marker, the file name, and the data after the marker.
|
||||
// If there is no next marker, find_file_marker returns fixNL(data), '', ''.
|
||||
fn find_file_marker(data string) (string, string, string) {
|
||||
mut i := 0
|
||||
for i < data.len {
|
||||
name, after := is_marker(data[i..])
|
||||
if name != '' {
|
||||
return data[..i], name, after
|
||||
}
|
||||
j := data[i..].index(txtar.nlm) or { return fix_nl(data), '', '' }
|
||||
i += j + 1 // positioned at start of new possible marker
|
||||
}
|
||||
return '', '', ''
|
||||
}
|
||||
|
||||
// is_marker checks whether the data begins with a file marker line.
|
||||
// If so, it returns the name from the line, and the data after the line.
|
||||
// Otherwise it returns name == "".
|
||||
fn is_marker(data string) (string, string) {
|
||||
if !data.starts_with(txtar.mstart) {
|
||||
return '', ''
|
||||
}
|
||||
mut ndata := data
|
||||
mut after := ''
|
||||
i := data.index_u8(`\n`)
|
||||
if i >= 0 {
|
||||
ndata, after = data[..i], data[i + 1..]
|
||||
}
|
||||
if !(ndata.ends_with(txtar.mend) && ndata.len >= txtar.mstart.len + txtar.mend.len) {
|
||||
return '', ''
|
||||
}
|
||||
name := ndata[txtar.mstart.len..ndata.len - txtar.mend.len].trim_space()
|
||||
return name, after
|
||||
}
|
||||
|
||||
// fix_nl returns the data, if it is empty, or if it ends in \n.
|
||||
// Otherwise it returns data + a final \n addded.
|
||||
fn fix_nl(data string) string {
|
||||
if data.len == 0 || data[data.len - 1] == `\n` {
|
||||
return data
|
||||
}
|
||||
return '${data}\n'
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue