all: require calling `optfn() ?` / `optfn() or {...}` for `fn optfn() ? {}`

pull/8357/head
Delyan Angelov 2021-01-26 16:43:10 +02:00
parent 97103f680a
commit e5a84719ca
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
90 changed files with 1994 additions and 1832 deletions

View File

@ -70,7 +70,8 @@ fn main() {
date := time.unix(commit_date.int()) date := time.unix(commit_date.int())
mut out := os.create('table.html') ? mut out := os.create('table.html') ?
// Place the new row on top // Place the new row on top
table = '<tr> table =
'<tr>
<td>$date.format()</td> <td>$date.format()</td>
<td><a target=_blank href="https://github.com/vlang/v/commit/$commit">$commit</a></td> <td><a target=_blank href="https://github.com/vlang/v/commit/$commit">$commit</a></td>
<td>$message</td> <td>$message</td>
@ -80,15 +81,15 @@ fn main() {
<td>${diff4}ms</td> <td>${diff4}ms</td>
</tr>\n' + </tr>\n' +
table.trim_space() table.trim_space()
out.writeln(table) out.writeln(table) ?
out.close() out.close()
// Regenerate index.html // Regenerate index.html
header := os.read_file('header.html') ? header := os.read_file('header.html') ?
footer := os.read_file('footer.html') ? footer := os.read_file('footer.html') ?
mut res := os.create('index.html') ? mut res := os.create('index.html') ?
res.writeln(header) res.writeln(header) ?
res.writeln(table) res.writeln(table) ?
res.writeln(footer) res.writeln(footer) ?
res.close() res.close()
} }
exec('git checkout master') exec('git checkout master')
@ -96,9 +97,7 @@ fn main() {
} }
fn exec(s string) string { fn exec(s string) string {
e := os.exec(s) or { e := os.exec(s) or { panic(err) }
panic(err)
}
return e.output.trim_right('\r\n') return e.output.trim_right('\r\n')
} }

View File

@ -12,21 +12,20 @@ pub fn set_verbose(on bool) {
// but V does not have globals normally. // but V does not have globals normally.
if on { if on {
os.setenv('VERBOSE', '1', true) os.setenv('VERBOSE', '1', true)
} } else {
else {
os.unsetenv('VERBOSE') os.unsetenv('VERBOSE')
} }
} }
pub fn cprintln(message string) { pub fn cprintln(message string) {
mut omessage := message mut omessage := message
omessage = if term_colors { term.green(omessage) } else { omessage } omessage = if scripting.term_colors { term.green(omessage) } else { omessage }
println(omessage) println(omessage)
} }
pub fn verbose_trace(label string, message string) { pub fn verbose_trace(label string, message string) {
if os.getenv('VERBOSE').len > 0 { if os.getenv('VERBOSE').len > 0 {
slabel := 'scripting.${label}' slabel := 'scripting.$label'
cprintln('# ${slabel:-25s} : $message') cprintln('# ${slabel:-25s} : $message')
} }
} }
@ -54,9 +53,9 @@ pub fn rmrf(path string) {
verbose_trace(@FN, 'rm -rf $path') verbose_trace(@FN, 'rm -rf $path')
if os.exists(path) { if os.exists(path) {
if os.is_dir(path) { if os.is_dir(path) {
os.rmdir_all(path) os.rmdir_all(path) or { panic(err) }
} else { } else {
os.rm(path) os.rm(path) or { panic(err) }
} }
} }
} }

View File

@ -210,7 +210,7 @@ pub fn (mut ts TestSession) test() {
// cleanup generated .tmp.c files after successfull tests: // cleanup generated .tmp.c files after successfull tests:
if ts.benchmark.nfail == 0 { if ts.benchmark.nfail == 0 {
if ts.rm_binaries { if ts.rm_binaries {
os.rmdir_all(ts.vtmp_dir) os.rmdir_all(ts.vtmp_dir) or { panic(err) }
} }
} }
} }
@ -241,7 +241,7 @@ fn worker_trunner(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
generated_binary_fpath := os.join_path(tmpd, generated_binary_fname) generated_binary_fpath := os.join_path(tmpd, generated_binary_fname)
if os.exists(generated_binary_fpath) { if os.exists(generated_binary_fpath) {
if ts.rm_binaries { if ts.rm_binaries {
os.rm(generated_binary_fpath) os.rm(generated_binary_fpath) or { panic(err) }
} }
} }
mut cmd_options := [ts.vargs] mut cmd_options := [ts.vargs]
@ -294,7 +294,7 @@ fn worker_trunner(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
} }
if os.exists(generated_binary_fpath) { if os.exists(generated_binary_fpath) {
if ts.rm_binaries { if ts.rm_binaries {
os.rm(generated_binary_fpath) os.rm(generated_binary_fpath) or { panic(err) }
} }
} }
return sync.no_result return sync.no_result
@ -422,7 +422,7 @@ pub fn header(msg string) {
pub fn setup_new_vtmp_folder() string { pub fn setup_new_vtmp_folder() string {
now := time.sys_mono_now() now := time.sys_mono_now()
new_vtmp_dir := os.join_path(os.temp_dir(), 'v', 'test_session_$now') new_vtmp_dir := os.join_path(os.temp_dir(), 'v', 'test_session_$now')
os.mkdir_all(new_vtmp_dir) os.mkdir_all(new_vtmp_dir) or { panic(err) }
os.setenv('VTMP', new_vtmp_dir, true) os.setenv('VTMP', new_vtmp_dir, true)
return new_vtmp_dir return new_vtmp_dir
} }

View File

@ -28,26 +28,26 @@ fn get_vexe_path() string {
fn new_tdir() string { fn new_tdir() string {
tdir_ := os.join_path(os.temp_dir(), rand.ulid()) tdir_ := os.join_path(os.temp_dir(), rand.ulid())
if os.exists(tdir_) { if os.exists(tdir_) {
os.rmdir(tdir_) os.rmdir(tdir_) or { panic(err) }
} }
os.mkdir(tdir_) os.mkdir(tdir_) or { panic(err) }
C.atexit(cleanup_tdir) C.atexit(cleanup_tdir)
return tdir_ return tdir_
} }
fn cleanup_tdir() { fn cleanup_tdir() {
println('... removing tdir: $tdir') println('... removing tdir: $tdir')
os.rmdir_all(tdir) os.rmdir_all(tdir) or { panic(err) }
} }
fn main() { fn main() {
println('> vroot: $vroot | vexe: $vexe | tdir: $tdir') println('> vroot: $vroot | vexe: $vexe | tdir: $tdir')
ok_fpath := os.join_path(tdir, 'single_test.v') ok_fpath := os.join_path(tdir, 'single_test.v')
os.write_file(ok_fpath, 'fn test_ok(){ assert true }') os.write_file(ok_fpath, 'fn test_ok(){ assert true }') ?
check_ok('"$vexe" $ok_fpath') check_ok('"$vexe" $ok_fpath')
check_ok('"$vexe" test $ok_fpath') check_ok('"$vexe" test $ok_fpath')
fail_fpath := os.join_path(tdir, 'failing_test.v') fail_fpath := os.join_path(tdir, 'failing_test.v')
os.write_file(fail_fpath, 'fn test_fail(){ assert 1 == 2 }') os.write_file(fail_fpath, 'fn test_fail(){ assert 1 == 2 }') ?
check_fail('"$vexe" $fail_fpath') check_fail('"$vexe" $fail_fpath')
check_fail('"$vexe" test $fail_fpath') check_fail('"$vexe" test $fail_fpath')
check_fail('"$vexe" test $tdir') check_fail('"$vexe" test $tdir')

View File

@ -68,7 +68,6 @@ fn (context Context) file2v(bname string, fbytes []byte, bn_max int) string {
sb.write('$b, ') sb.write('$b, ')
line_len += b.len + 2 line_len += b.len + 2
} }
} }
sb.write(']!\n') sb.write(']!\n')
return sb.str() return sb.str()
@ -76,8 +75,8 @@ fn (context Context) file2v(bname string, fbytes []byte, bn_max int) string {
fn (context Context) bname_and_bytes(file string) ?(string, []byte) { fn (context Context) bname_and_bytes(file string) ?(string, []byte) {
fname := os.file_name(file) fname := os.file_name(file)
fname_escpaed := fname.replace_each(['.', '_', '-', '_']) fname_escaped := fname.replace_each(['.', '_', '-', '_'])
byte_name := '$context.prefix$fname_escpaed'.to_lower() byte_name := '$context.prefix$fname_escaped'.to_lower()
fbytes := os.read_bytes(file) or { return error('Error: $err') } fbytes := os.read_bytes(file) or { return error('Error: $err') }
return byte_name, fbytes return byte_name, fbytes
} }
@ -131,12 +130,12 @@ fn main() {
} }
max_bname := context.max_bname_len(file_byte_map.keys()) max_bname := context.max_bname_len(file_byte_map.keys())
if context.write_file.len > 0 { if context.write_file.len > 0 {
mut out_file := os.create(context.write_file) or { panic(err) } mut out_file := os.create(context.write_file) ?
out_file.write_str(context.header()) out_file.write_str(context.header()) ?
for bname, fbytes in file_byte_map { for bname, fbytes in file_byte_map {
out_file.write_str(context.file2v(bname, fbytes, max_bname)) out_file.write_str(context.file2v(bname, fbytes, max_bname)) ?
} }
out_file.write_str(context.footer()) out_file.write_str(context.footer()) ?
} else { } else {
print(context.header()) print(context.header())
for bname, fbytes in file_byte_map { for bname, fbytes in file_byte_map {

View File

@ -55,9 +55,14 @@ fn main() {
// //
tpath := os.join_path(session.vtmp_dir, texe) tpath := os.join_path(session.vtmp_dir, texe)
if tname in tools_in_subfolders { if tname in tools_in_subfolders {
os.mv_by_cp(tpath, os.join_path(tfolder, tname, texe)) os.mv_by_cp(tpath, os.join_path(tfolder, tname, texe)) or { panic(err) }
continue
}
os.mv_by_cp(tpath, os.join_path(tfolder, texe)) or {
if !err.contains('vbuild-tools') {
eprintln(err)
}
continue continue
} }
os.mv_by_cp(tpath, os.join_path(tfolder, texe))
} }
} }

View File

@ -58,7 +58,7 @@ fn (c &Create) write_vmod(new bool) {
cerror(err) cerror(err)
exit(1) exit(1)
} }
vmod.write_str(vmod_content(c.name, c.description)) vmod.write_str(vmod_content(c.name, c.description)) or { panic(err) }
vmod.close() vmod.close()
} }
@ -67,12 +67,12 @@ fn (c &Create) write_main(new bool) {
return return
} }
main_path := if new { '$c.name/${c.name}.v' } else { '${c.name}.v' } main_path := if new { '$c.name/${c.name}.v' } else { '${c.name}.v' }
mut main := os.create(main_path) or { mut mainfile := os.create(main_path) or {
cerror(err) cerror(err)
exit(2) exit(2)
} }
main.write_str(main_content()) mainfile.write_str(main_content()) or { panic(err) }
main.close() mainfile.close()
} }
fn (c &Create) create_git_repo(dir string) { fn (c &Create) create_git_repo(dir string) {
@ -87,7 +87,7 @@ fn (c &Create) create_git_repo(dir string) {
// We don't really need a .gitignore, it's just a nice-to-have // We don't really need a .gitignore, it's just a nice-to-have
return return
} }
fl.write_str(gen_gitignore(c.name)) fl.write_str(gen_gitignore(c.name)) or { panic(err) }
fl.close() fl.close()
} }
} }
@ -110,9 +110,7 @@ fn create() {
} }
c.description = os.input('Input your project description: ') c.description = os.input('Input your project description: ')
println('Initialising ...') println('Initialising ...')
os.mkdir(c.name) or { os.mkdir(c.name) or { panic(err) }
panic(err)
}
c.write_vmod(true) c.write_vmod(true)
c.write_main(true) c.write_main(true)
c.create_git_repo(c.name) c.create_git_repo(c.name)

View File

@ -126,7 +126,7 @@ fn (vd VDoc) render_search_index(out Output) {
js_search_index.writeln('];') js_search_index.writeln('];')
js_search_data.writeln('];') js_search_data.writeln('];')
out_file_path := os.join_path(out.path, 'search_index.js') out_file_path := os.join_path(out.path, 'search_index.js')
os.write_file(out_file_path, js_search_index.str() + js_search_data.str()) os.write_file(out_file_path, js_search_index.str() + js_search_data.str()) or { panic(err) }
} }
fn (mut vd VDoc) render_static_html(out Output) { fn (mut vd VDoc) render_static_html(out Output) {
@ -162,7 +162,7 @@ fn (vd VDoc) get_resource(name string, out Output) string {
output_path := os.join_path(out.path, name) output_path := os.join_path(out.path, name)
if !os.exists(output_path) { if !os.exists(output_path) {
println('Generating $out.typ in "$output_path"') println('Generating $out.typ in "$output_path"')
os.write_file(output_path, res) os.write_file(output_path, res) or { panic(err) }
} }
return name return name
} }

View File

@ -162,7 +162,7 @@ fn (vd VDoc) work_processor(mut work sync.Channel, mut wg sync.WaitGroup) {
file_name, content := vd.render_doc(pdoc.d, pdoc.out) file_name, content := vd.render_doc(pdoc.d, pdoc.out)
output_path := os.join_path(pdoc.out.path, file_name) output_path := os.join_path(pdoc.out.path, file_name)
println('Generating $pdoc.out.typ in "$output_path"') println('Generating $pdoc.out.typ in "$output_path"')
os.write_file(output_path, content) os.write_file(output_path, content) or { panic(err) }
} }
wg.done() wg.done()
} }
@ -358,7 +358,7 @@ fn (mut vd VDoc) generate_docs_from_file() {
os.mkdir(out.path) or { panic(err) } os.mkdir(out.path) or { panic(err) }
} else { } else {
for fname in css_js_assets { for fname in css_js_assets {
os.rm(os.join_path(out.path, fname)) os.rm(os.join_path(out.path, fname)) or { panic(err) }
} }
} }
} }
@ -376,7 +376,7 @@ fn (mut vd VDoc) generate_docs_from_file() {
for favicon in favicons { for favicon in favicons {
favicon_path := os.join_path(favicons_path, favicon) favicon_path := os.join_path(favicons_path, favicon)
destination_path := os.join_path(out.path, favicon) destination_path := os.join_path(out.path, favicon)
os.cp(favicon_path, destination_path) os.cp(favicon_path, destination_path) or { panic(err) }
} }
} }
} }

View File

@ -176,7 +176,7 @@ fn (foptions &FormatOptions) format_file(file string) {
file_name := os.file_name(file) file_name := os.file_name(file)
ulid := rand.ulid() ulid := rand.ulid()
vfmt_output_path := os.join_path(vtmp_folder, 'vfmt_${ulid}_$file_name') vfmt_output_path := os.join_path(vtmp_folder, 'vfmt_${ulid}_$file_name')
os.write_file(vfmt_output_path, formatted_content) os.write_file(vfmt_output_path, formatted_content) or { panic(err) }
if foptions.is_verbose { if foptions.is_verbose {
eprintln('fmt.fmt worked and $formatted_content.len bytes were written to $vfmt_output_path .') eprintln('fmt.fmt worked and $formatted_content.len bytes were written to $vfmt_output_path .')
} }
@ -258,7 +258,8 @@ fn (foptions &FormatOptions) post_process_file(file string, formatted_file_path
} }
fn (f FormatOptions) str() string { fn (f FormatOptions) str() string {
return 'FormatOptions{ is_l: $f.is_l, is_w: $f.is_w, is_diff: $f.is_diff, is_verbose: $f.is_verbose,' + return
'FormatOptions{ is_l: $f.is_l, is_w: $f.is_w, is_diff: $f.is_diff, is_verbose: $f.is_verbose,' +
' is_all: $f.is_all, is_worker: $f.is_worker, is_debug: $f.is_debug, is_noerror: $f.is_noerror,' + ' is_all: $f.is_all, is_worker: $f.is_worker, is_debug: $f.is_debug, is_noerror: $f.is_noerror,' +
' is_verify: $f.is_verify" }' ' is_verify: $f.is_verify" }'
} }

View File

@ -71,9 +71,7 @@ fn main() {
'install' { 'install' {
if module_names.len == 0 && os.exists('./v.mod') { if module_names.len == 0 && os.exists('./v.mod') {
println('Detected v.mod file inside the project directory. Using it...') println('Detected v.mod file inside the project directory. Using it...')
manifest := vmod.from_file('./v.mod') or { manifest := vmod.from_file('./v.mod') or { panic(err) }
panic(err)
}
module_names = manifest.dependencies module_names = manifest.dependencies
} }
vpm_install(module_names) vpm_install(module_names)
@ -227,15 +225,11 @@ fn vpm_update(m []string) {
} }
mut errors := 0 mut errors := 0
for name in module_names { for name in module_names {
final_module_path := valid_final_path_of_existing_module(name) or { final_module_path := valid_final_path_of_existing_module(name) or { continue }
continue
}
os.chdir(final_module_path) os.chdir(final_module_path)
println('Updating module "$name"...') println('Updating module "$name"...')
verbose_println(' work folder: $final_module_path') verbose_println(' work folder: $final_module_path')
vcs := vcs_used_in_dir(final_module_path) or { vcs := vcs_used_in_dir(final_module_path) or { continue }
continue
}
vcs_cmd := supported_vcs_update_cmds[vcs[0]] vcs_cmd := supported_vcs_update_cmds[vcs[0]]
verbose_println(' command: $vcs_cmd') verbose_println(' command: $vcs_cmd')
vcs_res := os.exec('$vcs_cmd') or { vcs_res := os.exec('$vcs_cmd') or {
@ -265,13 +259,9 @@ fn get_outdated() ?[]string {
module_names := get_installed_modules() module_names := get_installed_modules()
mut outdated := []string{} mut outdated := []string{}
for name in module_names { for name in module_names {
final_module_path := valid_final_path_of_existing_module(name) or { final_module_path := valid_final_path_of_existing_module(name) or { continue }
continue
}
os.chdir(final_module_path) os.chdir(final_module_path)
vcs := vcs_used_in_dir(final_module_path) or { vcs := vcs_used_in_dir(final_module_path) or { continue }
continue
}
vcs_cmd_steps := supported_vcs_outdated_steps[vcs[0]] vcs_cmd_steps := supported_vcs_outdated_steps[vcs[0]]
mut outputs := []string{} mut outputs := []string{}
for step in vcs_cmd_steps { for step in vcs_cmd_steps {
@ -296,9 +286,7 @@ fn get_outdated() ?[]string {
} }
fn vpm_upgrade() { fn vpm_upgrade() {
outdated := get_outdated() or { outdated := get_outdated() or { exit(1) }
exit(1)
}
if outdated.len > 0 { if outdated.len > 0 {
vpm_update(outdated) vpm_update(outdated)
} else { } else {
@ -307,9 +295,7 @@ fn vpm_upgrade() {
} }
fn vpm_outdated() { fn vpm_outdated() {
outdated := get_outdated() or { outdated := get_outdated() or { exit(1) }
exit(1)
}
if outdated.len > 0 { if outdated.len > 0 {
println('Outdated modules:') println('Outdated modules:')
for m in outdated { for m in outdated {
@ -342,18 +328,16 @@ fn vpm_remove(module_names []string) {
exit(2) exit(2)
} }
for name in module_names { for name in module_names {
final_module_path := valid_final_path_of_existing_module(name) or { final_module_path := valid_final_path_of_existing_module(name) or { continue }
continue
}
println('Removing module "$name"...') println('Removing module "$name"...')
verbose_println('removing folder $final_module_path') verbose_println('removing folder $final_module_path')
os.rmdir_all(final_module_path) os.rmdir_all(final_module_path) or { panic(err) }
// delete author directory if it is empty // delete author directory if it is empty
author := name.split('.')[0] author := name.split('.')[0]
author_dir := os.real_path(os.join_path(settings.vmodules_path, author)) author_dir := os.real_path(os.join_path(settings.vmodules_path, author))
if os.is_dir_empty(author_dir) { if os.is_dir_empty(author_dir) {
verbose_println('removing author folder $author_dir') verbose_println('removing author folder $author_dir')
os.rmdir(author_dir) os.rmdir(author_dir) or { panic(err) }
} }
} }
} }
@ -380,9 +364,7 @@ fn valid_final_path_of_existing_module(name string) ?string {
fn ensure_vmodules_dir_exist() { fn ensure_vmodules_dir_exist() {
if !os.is_dir(settings.vmodules_path) { if !os.is_dir(settings.vmodules_path) {
println('Creating $settings.vmodules_path/ ...') println('Creating $settings.vmodules_path/ ...')
os.mkdir(settings.vmodules_path) or { os.mkdir(settings.vmodules_path) or { panic(err) }
panic(err)
}
} }
} }
@ -405,9 +387,7 @@ fn vcs_used_in_dir(dir string) ?[]string {
} }
fn get_installed_modules() []string { fn get_installed_modules() []string {
dirs := os.ls(settings.vmodules_path) or { dirs := os.ls(settings.vmodules_path) or { return [] }
return []
}
mut modules := []string{} mut modules := []string{}
for dir in dirs { for dir in dirs {
adir := os.join_path(settings.vmodules_path, dir) adir := os.join_path(settings.vmodules_path, dir)
@ -420,13 +400,9 @@ fn get_installed_modules() []string {
continue continue
} }
author := dir author := dir
mods := os.ls(adir) or { mods := os.ls(adir) or { continue }
continue
}
for m in mods { for m in mods {
vcs_used_in_dir(os.join_path(adir, m)) or { vcs_used_in_dir(os.join_path(adir, m)) or { continue }
continue
}
modules << '${author}.$m' modules << '${author}.$m'
} }
} }
@ -435,9 +411,7 @@ fn get_installed_modules() []string {
fn get_all_modules() []string { fn get_all_modules() []string {
url := get_working_server_url() url := get_working_server_url()
r := http.get(url) or { r := http.get(url) or { panic(err) }
panic(err)
}
if r.status_code != 200 { if r.status_code != 200 {
println('Failed to search vpm.vlang.io. Status code: $r.status_code') println('Failed to search vpm.vlang.io. Status code: $r.status_code')
exit(1) exit(1)
@ -476,9 +450,7 @@ fn resolve_dependencies(name string, module_path string, module_names []string)
if !os.exists(vmod_path) { if !os.exists(vmod_path) {
return return
} }
data := os.read_file(vmod_path) or { data := os.read_file(vmod_path) or { return }
return
}
vmod := parse_vmod(data) vmod := parse_vmod(data)
mut deps := []string{} mut deps := []string{}
// filter out dependencies that were already specified by the user // filter out dependencies that were already specified by the user
@ -502,9 +474,7 @@ fn parse_vmod(data string) Vmod {
'deps': '' 'deps': ''
} }
for key in keys { for key in keys {
mut key_index := data.index('$key:') or { mut key_index := data.index('$key:') or { continue }
continue
}
key_index += key.len + 1 key_index += key.len + 1
m[key] = data[key_index..data.index_after('\n', key_index)].trim_space().replace("'", m[key] = data[key_index..data.index_after('\n', key_index)].trim_space().replace("'",
'').replace('[', '').replace(']', '') '').replace('[', '').replace(']', '')
@ -519,7 +489,11 @@ fn parse_vmod(data string) Vmod {
} }
fn get_working_server_url() string { fn get_working_server_url() string {
server_urls := if settings.server_urls.len > 0 { settings.server_urls } else { default_vpm_server_urls } server_urls := if settings.server_urls.len > 0 {
settings.server_urls
} else {
default_vpm_server_urls
}
for url in server_urls { for url in server_urls {
verbose_println('Trying server url: $url') verbose_println('Trying server url: $url')
http.head(url) or { http.head(url) or {
@ -572,13 +546,11 @@ fn get_module_meta_info(name string) ?Mod {
continue continue
} }
if r.status_code == 404 || r.text.contains('404') { if r.status_code == 404 || r.text.contains('404') {
errors << errors << 'Skipping module "$name", since $server_url reported that "$name" does not exist.'
'Skipping module "$name", since $server_url reported that "$name" does not exist.'
continue continue
} }
if r.status_code != 200 { if r.status_code != 200 {
errors << errors << 'Skipping module "$name", since $server_url responded with $r.status_code http status code. Please try again later.'
'Skipping module "$name", since $server_url responded with $r.status_code http status code. Please try again later.'
continue continue
} }
s := r.text s := r.text

View File

@ -109,21 +109,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
if !is_stdin_a_pipe { if !is_stdin_a_pipe {
println('') println('')
} }
os.rm(file) cleanup_files([file, temp_file])
os.rm(temp_file)
$if windows {
os.rm(file[..file.len - 2] + '.exe')
os.rm(temp_file[..temp_file.len - 2] + '.exe')
$if msvc {
os.rm(file[..file.len - 2] + '.ilk')
os.rm(file[..file.len - 2] + '.pdb')
os.rm(temp_file[..temp_file.len - 2] + '.ilk')
os.rm(temp_file[..temp_file.len - 2] + '.pdb')
}
} $else {
os.rm(file[..file.len - 2])
os.rm(temp_file[..temp_file.len - 2])
}
} }
mut r := new_repl() mut r := new_repl()
vexe := os.getenv('VEXE') vexe := os.getenv('VEXE')
@ -198,7 +184,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
} }
if r.line.starts_with('print') { if r.line.starts_with('print') {
source_code := r.current_source_code(false) + '\n$r.line\n' source_code := r.current_source_code(false) + '\n$r.line\n'
os.write_file(file, source_code) os.write_file(file, source_code) or { panic(err) }
s := os.exec('"$vexe" -repl run "$file"') or { s := os.exec('"$vexe" -repl run "$file"') or {
rerror(err) rerror(err)
return return
@ -208,7 +194,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
mut temp_line := r.line mut temp_line := r.line
mut temp_flag := false mut temp_flag := false
func_call := r.function_call(r.line) func_call := r.function_call(r.line)
filter_line := r.line.replace(r.line.find_between("\'", "\'"), '').replace(r.line.find_between('"', filter_line := r.line.replace(r.line.find_between("'", "'"), '').replace(r.line.find_between('"',
'"'), '') '"'), '')
possible_statement_patterns := [ possible_statement_patterns := [
'=', '=',
@ -268,7 +254,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
} }
temp_source_code = r.current_source_code(true) + '\n$temp_line\n' temp_source_code = r.current_source_code(true) + '\n$temp_line\n'
} }
os.write_file(temp_file, temp_source_code) os.write_file(temp_file, temp_source_code) or { panic(err) }
s := os.exec('"$vexe" -repl run "$temp_file"') or { s := os.exec('"$vexe" -repl run "$temp_file"') or {
rerror(err) rerror(err)
return return
@ -355,3 +341,18 @@ fn (mut r Repl) get_one_line(prompt string) ?string {
rline := r.readline.read_line(prompt) or { return none } rline := r.readline.read_line(prompt) or { return none }
return rline return rline
} }
fn cleanup_files(files []string) {
for file in files {
os.rm(file) or { }
$if windows {
os.rm(file[..file.len - 2] + '.exe') or { }
$if msvc {
os.rm(file[..file.len - 2] + '.ilk') or { }
os.rm(file[..file.len - 2] + '.pdb') or { }
}
} $else {
os.rm(file[..file.len - 2]) or { }
}
}
}

View File

@ -4,6 +4,7 @@ import v.pref
$if windows { $if windows {
$if tinyc { $if tinyc {
#flag -lAdvapi32 #flag -lAdvapi32
#flag -lUser32 #flag -lUser32
} }
} }
@ -19,20 +20,16 @@ fn main() {
fn setup_symlink(vexe string) { fn setup_symlink(vexe string) {
link_dir := '/usr/local/bin' link_dir := '/usr/local/bin'
if !os.exists(link_dir) { if !os.exists(link_dir) {
os.mkdir_all(link_dir) os.mkdir_all(link_dir) or { panic(err) }
} }
mut link_path := link_dir + '/v' mut link_path := link_dir + '/v'
mut ret := os.exec('ln -sf $vexe $link_path') or { mut ret := os.exec('ln -sf $vexe $link_path') or { panic(err) }
panic(err)
}
if ret.exit_code == 0 { if ret.exit_code == 0 {
println('Symlink "$link_path" has been created') println('Symlink "$link_path" has been created')
} else if os.system("uname -o | grep -q \'[A/a]ndroid\'") == 0 { } else if os.system("uname -o | grep -q '[A/a]ndroid'") == 0 {
println('Failed to create symlink "$link_path". Trying again with Termux path for Android.') println('Failed to create symlink "$link_path". Trying again with Termux path for Android.')
link_path = '/data/data/com.termux/files/usr/bin/v' link_path = '/data/data/com.termux/files/usr/bin/v'
ret = os.exec('ln -sf $vexe $link_path') or { ret = os.exec('ln -sf $vexe $link_path') or { panic(err) }
panic(err)
}
if ret.exit_code == 0 { if ret.exit_code == 0 {
println('Symlink "$link_path" has been created') println('Symlink "$link_path" has been created')
} else { } else {
@ -52,9 +49,9 @@ fn setup_symlink_windows(vexe string) {
vsymlinkdir := os.join_path(vdir, '.bin') vsymlinkdir := os.join_path(vdir, '.bin')
mut vsymlink := os.join_path(vsymlinkdir, 'v.exe') mut vsymlink := os.join_path(vsymlinkdir, 'v.exe')
if !os.exists(vsymlinkdir) { if !os.exists(vsymlinkdir) {
os.mkdir_all(vsymlinkdir) // will panic if fails os.mkdir_all(vsymlinkdir) or { panic(err) } // will panic if fails
} else { } else {
os.rm(vsymlink) os.rm(vsymlink) or { panic(err) }
} }
// First, try to create a native symlink at .\.bin\v.exe // First, try to create a native symlink at .\.bin\v.exe
os.symlink(vsymlink, vexe) or { os.symlink(vsymlink, vexe) or {
@ -64,9 +61,9 @@ fn setup_symlink_windows(vexe string) {
eprintln('Creating a batch file instead...') eprintln('Creating a batch file instead...')
vsymlink = os.join_path(vsymlinkdir, 'v.bat') vsymlink = os.join_path(vsymlinkdir, 'v.bat')
if os.exists(vsymlink) { if os.exists(vsymlink) {
os.rm(vsymlink) os.rm(vsymlink) or { panic(err) }
} }
os.write_file(vsymlink, '@echo off\n$vexe %*') os.write_file(vsymlink, '@echo off\n$vexe %*') or { panic(err) }
eprintln('$vsymlink file written.') eprintln('$vsymlink file written.')
} }
if !os.exists(vsymlink) { if !os.exists(vsymlink) {
@ -83,9 +80,7 @@ fn setup_symlink_windows(vexe string) {
// C.RegCloseKey(reg_sys_env_handle) // C.RegCloseKey(reg_sys_env_handle)
// } // }
// if the above succeeded, and we cannot get the value, it may simply be empty // if the above succeeded, and we cannot get the value, it may simply be empty
sys_env_path := get_reg_value(reg_sys_env_handle, 'Path') or { sys_env_path := get_reg_value(reg_sys_env_handle, 'Path') or { '' }
''
}
current_sys_paths := sys_env_path.split(os.path_delimiter).map(it.trim('/$os.path_separator')) current_sys_paths := sys_env_path.split(os.path_delimiter).map(it.trim('/$os.path_separator'))
mut new_paths := [vsymlinkdir] mut new_paths := [vsymlinkdir]
for p in current_sys_paths { for p in current_sys_paths {
@ -171,8 +166,7 @@ fn set_reg_value(reg_key voidptr, key string, value string) ?bool {
// letting them know that the system environment has changed and should be reloaded // letting them know that the system environment has changed and should be reloaded
fn send_setting_change_msg(message_data string) ?bool { fn send_setting_change_msg(message_data string) ?bool {
$if windows { $if windows {
if C.SendMessageTimeout(os.hwnd_broadcast, os.wm_settingchange, 0, message_data.to_wide(), os.smto_abortifhung, 5000, 0) == if C.SendMessageTimeout(os.hwnd_broadcast, os.wm_settingchange, 0, message_data.to_wide(), os.smto_abortifhung, 5000, 0) == 0 {
0 {
return error('Could not broadcast WM_SETTINGCHANGE') return error('Could not broadcast WM_SETTINGCHANGE')
} }
return true return true

View File

@ -108,9 +108,9 @@ fn (app App) show_current_v_version() {
fn (app App) backup(file string) { fn (app App) backup(file string) {
backup_file := '${file}_old.exe' backup_file := '${file}_old.exe'
if os.exists(backup_file) { if os.exists(backup_file) {
os.rm(backup_file) os.rm(backup_file) or { panic(err) }
} }
os.mv(file, backup_file) os.mv(file, backup_file) or { panic(err) }
} }
fn (app App) git_command(command string) { fn (app App) git_command(command string) {

View File

@ -7,7 +7,7 @@ fn main() {
mut cm := vcache.new_cache_manager([]) mut cm := vcache.new_cache_manager([])
cpath := cm.basepath cpath := cm.basepath
if os.exists(cpath) && os.is_dir(cpath) { if os.exists(cpath) && os.is_dir(cpath) {
os.rmdir_all(cpath) os.rmdir_all(cpath) or { }
} }
println('V cache folder $cpath was wiped.') println('V cache folder $cpath was wiped.')
} }

View File

@ -4,7 +4,9 @@ import io
fn main() { fn main() {
// Make a new connection // Make a new connection
mut conn := net.dial_tcp('google.com:80') ? mut conn := net.dial_tcp('google.com:80') ?
defer { conn.close() } defer {
conn.close() or { }
}
// Simple http HEAD request for a file // Simple http HEAD request for a file
conn.write_str('HEAD /index.html HTTP/1.0\r\n\r\n') ? conn.write_str('HEAD /index.html HTTP/1.0\r\n\r\n') ?
// Read all the data that is waiting // Read all the data that is waiting

View File

@ -35,7 +35,7 @@ const (
f_0 = 0.0 f_0 = 0.0
) )
/***************************** 3D Vector utility struct **********************/ //**************************** 3D Vector utility struct *********************
struct Vec { struct Vec {
mut: mut:
x f64 = 0.0 x f64 = 0.0
@ -70,11 +70,7 @@ fn (v Vec) mult_s (b f64) Vec{
[inline] [inline]
fn (v Vec) cross(b Vec) Vec { fn (v Vec) cross(b Vec) Vec {
return Vec{ return Vec{v.y * b.z - v.z * b.y, v.z * b.x - v.x * b.z, v.x * b.y - v.y * b.x}
v.y * b.z - v.z * b.y,
v.z * b.x - v.x * b.z,
v.x * b.y - v.y * b.x
}
} }
[inline] [inline]
@ -83,7 +79,7 @@ fn (v Vec) norm () Vec {
return Vec{v.x * tmp_norm, v.y * tmp_norm, v.z * tmp_norm} return Vec{v.x * tmp_norm, v.y * tmp_norm, v.z * tmp_norm}
} }
/*********************************Image***************************************/ //********************************Image**************************************
struct Image { struct Image {
width int width int
height int height int
@ -93,8 +89,8 @@ struct Image {
fn new_image(w int, h int) Image { fn new_image(w int, h int) Image {
vecsize := int(sizeof(Vec)) vecsize := int(sizeof(Vec))
return Image{ return Image{
width: w, width: w
height: h, height: h
data: &Vec(vcalloc(vecsize * w * h)) data: &Vec(vcalloc(vecsize * w * h))
} }
} }
@ -103,19 +99,19 @@ fn new_image(w int, h int) Image {
fn (image Image) save_as_ppm(file_name string) { fn (image Image) save_as_ppm(file_name string) {
npixels := image.width * image.height npixels := image.width * image.height
mut f_out := os.create(file_name) or { panic(err) } mut f_out := os.create(file_name) or { panic(err) }
f_out.writeln('P3') f_out.writeln('P3') or { panic(err) }
f_out.writeln('${image.width} ${image.height}') f_out.writeln('$image.width $image.height') or { panic(err) }
f_out.writeln('255') f_out.writeln('255') or { panic(err) }
for i in 0 .. npixels { for i in 0 .. npixels {
c_r := to_int(unsafe { image.data[i] }.x) c_r := to_int(unsafe { image.data[i] }.x)
c_g := to_int(unsafe { image.data[i] }.y) c_g := to_int(unsafe { image.data[i] }.y)
c_b := to_int(unsafe { image.data[i] }.z) c_b := to_int(unsafe { image.data[i] }.z)
f_out.write_str('$c_r $c_g $c_b ') f_out.write_str('$c_r $c_g $c_b ') or { panic(err) }
} }
f_out.close() f_out.close()
} }
/*********************************** Ray *************************************/ //********************************** Ray ************************************
struct Ray { struct Ray {
o Vec o Vec
d Vec d Vec
@ -128,7 +124,7 @@ enum Refl_t {
refr refr
} }
/********************************* Sphere ************************************/ //******************************** Sphere ***********************************
struct Sphere { struct Sphere {
rad f64 = 0.0 // radius rad f64 = 0.0 // radius
p Vec // position p Vec // position
@ -169,48 +165,147 @@ fn (sp Sphere) intersect (r Ray) f64 {
const ( const (
cen = Vec{50, 40.8, -860} // used by scene 1 cen = Vec{50, 40.8, -860} // used by scene 1
spheres = [ spheres = [
[// scene 0 cornnel box [/* scene 0 cornnel box */ Sphere{
Sphere{rad: 1e+5, p: Vec{ 1e+5 +1,40.8,81.6} , e: Vec{} , c: Vec{.75,.25,.25} , refl: .diff},//Left rad: 1e+5
Sphere{rad: 1e+5, p: Vec{-1e+5 +99,40.8,81.6}, e: Vec{} , c: Vec{.25,.25,.75} , refl: .diff},//Rght p: Vec{1e+5 + 1, 40.8, 81.6}
Sphere{rad: 1e+5, p: Vec{50,40.8, 1e+5} , e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Back e: Vec{}
Sphere{rad: 1e+5, p: Vec{50,40.8,-1e+5 +170} , e: Vec{} , c: Vec{} , refl: .diff},//Frnt c: Vec{.75, .25, .25}
Sphere{rad: 1e+5, p: Vec{50, 1e+5, 81.6} , e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Botm refl: .diff
Sphere{rad: 1e+5, p: Vec{50,-1e+5 +81.6,81.6}, e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Top }, /* Left */ Sphere{
Sphere{rad: 16.5, p: Vec{27,16.5,47} , e: Vec{} , c: Vec{1,1,1}.mult_s(.999) , refl: .spec},//Mirr rad: 1e+5
Sphere{rad: 16.5, p: Vec{73,16.5,78} , e: Vec{} , c: Vec{1,1,1}.mult_s(.999) , refl: .refr},//Glas p: Vec{-1e+5 + 99, 40.8, 81.6}
Sphere{rad: 600 , p: Vec{50,681.6-.27,81.6} , e: Vec{12,12,12}, c: Vec{}, refl: .diff} //Lite e: Vec{}
], c: Vec{.25, .25, .75}
refl: .diff
[// scene 1 sunset }, /* Rght */ Sphere{
Sphere{rad: 1600, p: Vec{1.0,0.0,2.0}.mult_s(3000), e: Vec{1.0,.9,.8}.mult_s(1.2e+1*1.56*2) , c: Vec{} , refl: .diff}, // sun rad: 1e+5
Sphere{rad: 1560, p: Vec{1,0,2}.mult_s(3500) , e: Vec{1.0,.5,.05}.mult_s(4.8e+1*1.56*2) , c: Vec{} , refl: .diff}, // horizon sun2 p: Vec{50, 40.8, 1e+5}
Sphere{rad: 10000, p: cen+Vec{0,0,-200}, e: Vec{0.00063842, 0.02001478, 0.28923243}.mult_s(6e-2*8), c: Vec{.7,.7,1}.mult_s(.25), refl: .diff}, // sky e: Vec{}
c: Vec{.75, .75, .75}
Sphere{rad: 100000, p: Vec{50, -100000, 0} , e: Vec{} , c: Vec{.3,.3,.3} , refl: .diff}, // grnd refl: .diff
Sphere{rad: 110000, p: Vec{50, -110048.5, 0} , e: Vec{.9,.5,.05}.mult_s(4) , c: Vec{}, refl: .diff},// horizon brightener }, /* Back */ Sphere{
Sphere{rad: 4e+4 , p: Vec{50, -4e+4-30, -3000}, e: Vec{} , c: Vec{.2,.2,.2} , refl: .diff},// mountains rad: 1e+5
p: Vec{50, 40.8, -1e+5 + 170}
Sphere{rad: 26.5, p: Vec{22,26.5,42}, e: Vec{}, c: Vec{1,1,1}.mult_s(.596) , refl: .spec}, // white Mirr e: Vec{}
Sphere{rad: 13, p: Vec{75,13,82 }, e: Vec{}, c: Vec{.96,.96,.96}.mult_s(.96), refl: .refr},// Glas c: Vec{}
Sphere{rad: 22, p: Vec{87,22,24 }, e: Vec{}, c: Vec{.6,.6,.6}.mult_s(.696) , refl: .refr} // Glas2 refl: .diff
], }, /* Frnt */ Sphere{
rad: 1e+5
p: Vec{50, 1e+5, 81.6}
[// scene 3 Psychedelic e: Vec{}
Sphere{rad: 150, p: Vec{50+75,28,62}, e: Vec{1,1,1}.mult_s(0e-3), c: Vec{1,.9,.8}.mult_s(.93), refl: .refr}, c: Vec{.75, .75, .75}
Sphere{rad: 28 , p: Vec{50+5,-28,62}, e: Vec{1,1,1}.mult_s(1e+1), c: Vec{1,1,1}.mult_s(0) , refl: .diff}, refl: .diff
Sphere{rad: 300, p: Vec{50,28,62} , e: Vec{1,1,1}.mult_s(0e-3), c: Vec{1,1,1}.mult_s(.93) , refl: .spec} }, /* Botm */ Sphere{
] rad: 1e+5
p: Vec{50, -1e+5 + 81.6, 81.6}
e: Vec{}
c: Vec{.75, .75, .75}
refl: .diff
}, /* Top */ Sphere{
rad: 16.5
p: Vec{27, 16.5, 47}
e: Vec{}
c: Vec{1, 1, 1}.mult_s(.999)
refl: .spec
}, /* Mirr */ Sphere{
rad: 16.5
p: Vec{73, 16.5, 78}
e: Vec{}
c: Vec{1, 1, 1}.mult_s(.999)
refl: .refr
}, /* Glas */ Sphere{
rad: 600
p: Vec{50, 681.6 - .27, 81.6}
e: Vec{12, 12, 12}
c: Vec{}
refl: .diff
} /* Lite */],
[/* scene 1 sunset */ Sphere{
rad: 1600
p: Vec{1.0, 0.0, 2.0}.mult_s(3000)
e: Vec{1.0, .9, .8}.mult_s(1.2e+1 * 1.56 * 2)
c: Vec{}
refl: .diff
}, /* sun */ Sphere{
rad: 1560
p: Vec{1, 0, 2}.mult_s(3500)
e: Vec{1.0, .5, .05}.mult_s(4.8e+1 * 1.56 * 2)
c: Vec{}
refl: .diff
}, /* horizon sun2 */ Sphere{
rad: 10000
p: cen + Vec{0, 0, -200}
e: Vec{0.00063842, 0.02001478, 0.28923243}.mult_s(6e-2 * 8)
c: Vec{.7, .7, 1}.mult_s(.25)
refl: .diff
}, /* sky */ Sphere{
rad: 100000
p: Vec{50, -100000, 0}
e: Vec{}
c: Vec{.3, .3, .3}
refl: .diff
}, /* grnd */ Sphere{
rad: 110000
p: Vec{50, -110048.5, 0}
e: Vec{.9, .5, .05}.mult_s(4)
c: Vec{}
refl: .diff
}, /* horizon brightener */ Sphere{
rad: 4e+4
p: Vec{50, -4e+4 - 30, -3000}
e: Vec{}
c: Vec{.2, .2, .2}
refl: .diff
}, /* mountains */ Sphere{
rad: 26.5
p: Vec{22, 26.5, 42}
e: Vec{}
c: Vec{1, 1, 1}.mult_s(.596)
refl: .spec
}, /* white Mirr */ Sphere{
rad: 13
p: Vec{75, 13, 82}
e: Vec{}
c: Vec{.96, .96, .96}.mult_s(.96)
refl: .refr
}, /* Glas */ Sphere{
rad: 22
p: Vec{87, 22, 24}
e: Vec{}
c: Vec{.6, .6, .6}.mult_s(.696)
refl: .refr
} /* Glas2 */],
[/* scene 3 Psychedelic */ Sphere{
rad: 150
p: Vec{50 + 75, 28, 62}
e: Vec{1, 1, 1}.mult_s(0e-3)
c: Vec{1, .9, .8}.mult_s(.93)
refl: .refr
}, Sphere{
rad: 28
p: Vec{50 + 5, -28, 62}
e: Vec{1, 1, 1}.mult_s(1e+1)
c: Vec{1, 1, 1}.mult_s(0)
refl: .diff
}, Sphere{
rad: 300
p: Vec{50, 28, 62}
e: Vec{1, 1, 1}.mult_s(0e-3)
c: Vec{1, 1, 1}.mult_s(.93)
refl: .spec
}],
] // end of scene array ] // end of scene array
) )
/*********************************** Utilities *******************************/ //********************************** Utilities ******************************
[inline] [inline]
fn clamp(x f64) f64 { fn clamp(x f64) f64 {
if x < 0 { return 0 } if x < 0 {
if x > 1 { return 1 } return 0
}
if x > 1 {
return 1
}
return x return x
} }
@ -262,12 +357,12 @@ fn new_tabs() Cache {
return c return c
} }
/************* Cache for sin/cos speed-up table and scene selector ***********/ //************ Cache for sin/cos speed-up table and scene selector **********
const ( const (
tabs = new_tabs() tabs = new_tabs()
) )
/******************* main function for the radiance calculation **************/ //****************** main function for the radiance calculation *************
fn radiance(r Ray, depthi int, scene_id int) Vec { fn radiance(r Ray, depthi int, scene_id int) Vec {
if depthi > 1024 { if depthi > 1024 {
eprintln('depthi: $depthi') eprintln('depthi: $depthi')
@ -284,7 +379,10 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
scene := spheres[scene_id] scene := spheres[scene_id]
// res, t, id = intersect(r, id, tb.scene) // res, t, id = intersect(r, id, tb.scene)
res, t, id = intersect(r, scene.data, scene.len) res, t, id = intersect(r, scene.data, scene.len)
if !res { return Vec{} } //if miss, return black if !res {
return Vec{}
}
// if miss, return black
obj := scene[id] // the hit object obj := scene[id] // the hit object
@ -326,11 +424,7 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
w := nl w := nl
mut u := if math.abs(w.x) > f64(0.1) { mut u := if math.abs(w.x) > f64(0.1) { Vec{0, 1, 0} } else { Vec{1, 0, 0} }
Vec{0, 1, 0}
} else {
Vec{1, 0, 0}
}
u = u.cross(w).norm() u = u.cross(w).norm()
v := w.cross(u) v := w.cross(u)
@ -339,7 +433,8 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
// d := (u.mult_s(math.cos(r1) * r2s) + v.mult_s(math.sin(r1) * r2s) + w.mult_s(1.0 - r2)).norm() // d := (u.mult_s(math.cos(r1) * r2s) + v.mult_s(math.sin(r1) * r2s) + w.mult_s(1.0 - r2)).norm()
// tabbed speed-up // tabbed speed-up
d := (u.mult_s(tabs.cos_tab[r1] * r2s) + v.mult_s(tabs.sin_tab[r1] * r2s) + w.mult_s(math.sqrt(f64(1.0) - r2))).norm() d := (u.mult_s(tabs.cos_tab[r1] * r2s) + v.mult_s(tabs.sin_tab[r1] * r2s) +
w.mult_s(math.sqrt(f64(1.0) - r2))).norm()
return obj.e + f * radiance(Ray{x, d}, depth, scene_id) return obj.e + f * radiance(Ray{x, d}, depth, scene_id)
} else { } else {
@ -379,18 +474,16 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
mut tmp := Vec{} mut tmp := Vec{}
if depth > 2 { if depth > 2 {
// Russian roulette // Russian roulette
tmp = if rand_f64() < pp { tmp = if rand_f64() < pp { radiance(refl_ray, depth, scene_id).mult_s(rp) } else { radiance(Ray{x, tdir},
radiance(refl_ray, depth, scene_id).mult_s(rp) depth, scene_id).mult_s(tp) }
} else { } else {
radiance(Ray{x, tdir}, depth, scene_id).mult_s(tp) tmp = (radiance(refl_ray, depth, scene_id).mult_s(re)) +
} (radiance(Ray{x, tdir}, depth, scene_id).mult_s(tr))
} else {
tmp = (radiance(refl_ray, depth, scene_id).mult_s(re)) + (radiance( Ray{x, tdir}, depth, scene_id).mult_s(tr))
} }
return obj.e + (f * tmp) return obj.e + (f * tmp)
} }
/************************ beam scan routine **********************************/ //*********************** beam scan routine *********************************
fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image { fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image {
image := new_image(w, h) image := new_image(w, h)
@ -410,9 +503,8 @@ fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image {
// OpenMP injection point! #pragma omp parallel for schedule(dynamic, 1) shared(c) // OpenMP injection point! #pragma omp parallel for schedule(dynamic, 1) shared(c)
for y := 0; y < h; y++ { for y := 0; y < h; y++ {
eprint("\rRendering (${samps * 4} spp) ${(100.0 * f64(y)) / (f64(h) - 1.0):5.2f}%") eprint('\rRendering (${samps * 4} spp) ${(100.0 * f64(y)) / (f64(h) - 1.0):5.2f}%')
for x in 0 .. w { for x in 0 .. w {
i := (h - y - 1) * w + x i := (h - y - 1) * w + x
mut ivec := unsafe { &image.data[i] } mut ivec := unsafe { &image.data[i] }
// we use sx and sy to perform a square subsampling of 4 samples // we use sx and sy to perform a square subsampling of 4 samples
@ -428,7 +520,8 @@ fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image {
d := cx.mult_s(((f64(sx) + 0.5 + dx) * 0.5 + f64(x)) * w1 - .5) + d := cx.mult_s(((f64(sx) + 0.5 + dx) * 0.5 + f64(x)) * w1 - .5) +
cy.mult_s(((f64(sy) + 0.5 + dy) * 0.5 + f64(y)) * h1 - .5) + cam.d cy.mult_s(((f64(sy) + 0.5 + dy) * 0.5 + f64(y)) * h1 - .5) + cam.d
r = r + radiance(Ray{cam.o+d.mult_s(140.0), d.norm()}, 0, scene_id).mult_s(samps1) r = r + radiance(Ray{cam.o +
d.mult_s(140.0), d.norm()}, 0, scene_id).mult_s(samps1)
} }
tmp_vec := Vec{clamp(r.x), clamp(r.y), clamp(r.z)}.mult_s(.25) tmp_vec := Vec{clamp(r.x), clamp(r.y), clamp(r.z)}.mult_s(.25)
(*ivec) = *ivec + tmp_vec (*ivec) = *ivec + tmp_vec
@ -465,7 +558,6 @@ fn main() {
if os.args.len == 6 { if os.args.len == 6 {
height = os.args[5].int() height = os.args[5].int()
} }
// change the seed for a different result // change the seed for a different result
rand.seed([u32(2020), 0]) rand.seed([u32(2020), 0])
@ -474,11 +566,10 @@ fn main() {
image := ray_trace(width, height, samples, file_name, scene_id) image := ray_trace(width, height, samples, file_name, scene_id)
t2 := time.ticks() t2 := time.ticks()
eprintln('\nRendering finished. Took: ${(t2 - t1):5}ms') eprintln('\nRendering finished. Took: ${(t2 - t1):5}ms')
image.save_as_ppm(file_name) image.save_as_ppm(file_name)
t3 := time.ticks() t3 := time.ticks()
eprintln('Image saved as [${file_name}]. Took: ${(t3-t2):5}ms') eprintln('Image saved as [$file_name]. Took: ${(t3 - t2):5}ms')
} }

View File

@ -2,12 +2,12 @@ import term.ui as tui
const ( const (
colors = [ colors = [
tui.Color{33, 150, 243} tui.Color{33, 150, 243},
tui.Color{0, 150, 136} tui.Color{0, 150, 136},
tui.Color{205, 220, 57} tui.Color{205, 220, 57},
tui.Color{255, 152, 0} tui.Color{255, 152, 0},
tui.Color{244, 67, 54} tui.Color{244, 67, 54},
tui.Color{156, 39, 176} tui.Color{156, 39, 176},
] ]
) )
@ -66,27 +66,33 @@ fn event(e &tui.Event, x voidptr) {
} }
.space, .enter { .space, .enter {
app.color_idx++ app.color_idx++
if app.color_idx == colors.len { app.color_idx = 0 } if app.color_idx == colors.len {
app.color = colors[app.color_idx] app.color_idx = 0
} else {}
} }
} .mouse_move, .mouse_drag, .mouse_down { app.color = colors[app.color_idx]
}
else {}
}
}
.mouse_move, .mouse_drag, .mouse_down {
app.points << Point{e.x, e.y} app.points << Point{e.x, e.y}
} .mouse_scroll { }
.mouse_scroll {
d := if e.direction == .up { 0.1 } else { -0.1 } d := if e.direction == .up { 0.1 } else { -0.1 }
app.cut_rate += d app.cut_rate += d
if app.cut_rate < 1 { app.cut_rate = 1 } if app.cut_rate < 1 {
} else {} app.cut_rate = 1
}
}
else {}
} }
} }
mut app := &App{} mut app := &App{}
app.tui = tui.init( app.tui = tui.init(
user_data: app, user_data: app
frame_fn: frame, frame_fn: frame
event_fn: event, event_fn: event
hide_cursor: true hide_cursor: true
) )
app.tui.run() ?
app.tui.run()

View File

@ -11,29 +11,35 @@ fn event(e &tui.Event, x voidptr) {
app.tui.set_cursor_position(0, 0) app.tui.set_cursor_position(0, 0)
app.tui.write('V term.input event viewer (press `esc` to exit)\n\n') app.tui.write('V term.input event viewer (press `esc` to exit)\n\n')
app.tui.write('$e') app.tui.write('$e')
app.tui.write('\n\nRaw event bytes: "${e.utf8.bytes().hex()}" = ${e.utf8.bytes()}') app.tui.write('\n\nRaw event bytes: "$e.utf8.bytes().hex()" = $e.utf8.bytes()')
if e.modifiers != 0 { if e.modifiers != 0 {
app.tui.write('\nModifiers: $e.modifiers = ') app.tui.write('\nModifiers: $e.modifiers = ')
if e.modifiers & tui.ctrl != 0 { app.tui.write('ctrl. ') } if e.modifiers & tui.ctrl != 0 {
if e.modifiers & tui.shift != 0 { app.tui.write('shift ') } app.tui.write('ctrl. ')
if e.modifiers & tui.alt != 0 { app.tui.write('alt. ') } }
if e.modifiers & tui.shift != 0 {
app.tui.write('shift ')
}
if e.modifiers & tui.alt != 0 {
app.tui.write('alt. ')
}
} }
app.tui.flush() app.tui.flush()
if e.typ == .key_down && e.code == .escape { exit(0) } if e.typ == .key_down && e.code == .escape {
exit(0)
}
} }
mut app := &App{} mut app := &App{}
app.tui = tui.init( app.tui = tui.init(
user_data: app, user_data: app
event_fn: event event_fn: event
window_title: 'V term.ui event viewer' window_title: 'V term.ui event viewer'
hide_cursor: true hide_cursor: true
capture_events: true capture_events: true
frame_rate: 60 frame_rate: 60
use_alternate_buffer: false use_alternate_buffer: false
) )
println('V term.ui event viewer (press `esc` to exit)\n\n') println('V term.ui event viewer (press `esc` to exit)\n\n')
app.tui.run() app.tui.run() ?

View File

@ -35,10 +35,10 @@ fn (mut a App) init() {
a.width = w a.width = w
a.height = h a.height = h
term.erase_del_clear() term.erase_del_clear()
term.set_cursor_position({ term.set_cursor_position(
x: 0 x: 0
y: 0 y: 0
}) )
} }
fn (mut a App) start_game() { fn (mut a App) start_game() {
@ -66,10 +66,10 @@ fn (mut a App) quit() {
a.game.quit() a.game.quit()
return return
} }
term.set_cursor_position({ term.set_cursor_position(
x: 0 x: 0
y: 0 y: 0
}) )
exit(0) exit(0)
} }
@ -482,7 +482,7 @@ fn event(e &ui.Event, x voidptr) {
// main // main
mut app := &App{} mut app := &App{}
app.tui = ui.init({ app.tui = ui.init(
user_data: app user_data: app
init_fn: init init_fn: init
frame_fn: frame frame_fn: frame
@ -492,5 +492,5 @@ app.tui = ui.init({
capture_events: true capture_events: true
hide_cursor: true hide_cursor: true
frame_rate: 60 frame_rate: 60
}) )
app.tui.run() app.tui.run() ?

View File

@ -43,20 +43,28 @@ fn event(e &tui.Event, x voidptr) {
.mouse_drag { .mouse_drag {
app.cur_rect.x2 = e.x app.cur_rect.x2 = e.x
app.cur_rect.y2 = e.y app.cur_rect.y2 = e.y
} .mouse_up { }
.mouse_up {
app.rects << app.cur_rect app.rects << app.cur_rect
app.is_drag = false app.is_drag = false
} .key_down { }
if e.code == .c { app.rects.clear() } .key_down {
else if e.code == .escape { exit(0) } if e.code == .c {
} else {} app.rects.clear()
} else if e.code == .escape {
exit(0)
}
}
else {}
} }
app.redraw = true app.redraw = true
} }
fn frame(x voidptr) { fn frame(x voidptr) {
mut app := &App(x) mut app := &App(x)
if !app.redraw { return } if !app.redraw {
return
}
app.tui.clear() app.tui.clear()
@ -76,15 +84,12 @@ fn frame(x voidptr) {
app.redraw = false app.redraw = false
} }
mut app := &App{} mut app := &App{}
app.tui = tui.init( app.tui = tui.init(
user_data: app, user_data: app
event_fn: event, event_fn: event
frame_fn: frame frame_fn: frame
hide_cursor: true hide_cursor: true
frame_rate: 60 frame_rate: 60
) )
app.tui.run() ?
app.tui.run()

View File

@ -3,73 +3,73 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module main module main
import term.ui as tui import term.ui
// The color palette, taken from Google's Material design // The color palette, taken from Google's Material design
const ( const (
colors = [ colors = [
[ [
tui.Color{239, 154, 154}, ui.Color{239, 154, 154},
tui.Color{244, 143, 177}, ui.Color{244, 143, 177},
tui.Color{206, 147, 216}, ui.Color{206, 147, 216},
tui.Color{179, 157, 219}, ui.Color{179, 157, 219},
tui.Color{159, 168, 218}, ui.Color{159, 168, 218},
tui.Color{144, 202, 249}, ui.Color{144, 202, 249},
tui.Color{129, 212, 250}, ui.Color{129, 212, 250},
tui.Color{128, 222, 234}, ui.Color{128, 222, 234},
tui.Color{128, 203, 196}, ui.Color{128, 203, 196},
tui.Color{165, 214, 167}, ui.Color{165, 214, 167},
tui.Color{197, 225, 165}, ui.Color{197, 225, 165},
tui.Color{230, 238, 156}, ui.Color{230, 238, 156},
tui.Color{255, 245, 157}, ui.Color{255, 245, 157},
tui.Color{255, 224, 130}, ui.Color{255, 224, 130},
tui.Color{255, 204, 128}, ui.Color{255, 204, 128},
tui.Color{255, 171, 145}, ui.Color{255, 171, 145},
tui.Color{188, 170, 164}, ui.Color{188, 170, 164},
tui.Color{238, 238, 238}, ui.Color{238, 238, 238},
tui.Color{176, 190, 197}, ui.Color{176, 190, 197},
], ],
[ [
tui.Color{244, 67, 54}, ui.Color{244, 67, 54},
tui.Color{233, 30, 99}, ui.Color{233, 30, 99},
tui.Color{156, 39, 176}, ui.Color{156, 39, 176},
tui.Color{103, 58, 183}, ui.Color{103, 58, 183},
tui.Color{63, 81, 181}, ui.Color{63, 81, 181},
tui.Color{33, 150, 243}, ui.Color{33, 150, 243},
tui.Color{3, 169, 244}, ui.Color{3, 169, 244},
tui.Color{0, 188, 212}, ui.Color{0, 188, 212},
tui.Color{0, 150, 136}, ui.Color{0, 150, 136},
tui.Color{76, 175, 80}, ui.Color{76, 175, 80},
tui.Color{139, 195, 74}, ui.Color{139, 195, 74},
tui.Color{205, 220, 57}, ui.Color{205, 220, 57},
tui.Color{255, 235, 59}, ui.Color{255, 235, 59},
tui.Color{255, 193, 7}, ui.Color{255, 193, 7},
tui.Color{255, 152, 0}, ui.Color{255, 152, 0},
tui.Color{255, 87, 34}, ui.Color{255, 87, 34},
tui.Color{121, 85, 72}, ui.Color{121, 85, 72},
tui.Color{120, 120, 120}, ui.Color{120, 120, 120},
tui.Color{96, 125, 139}, ui.Color{96, 125, 139},
], ],
[ [
tui.Color{198, 40, 40}, ui.Color{198, 40, 40},
tui.Color{173, 20, 87}, ui.Color{173, 20, 87},
tui.Color{106, 27, 154}, ui.Color{106, 27, 154},
tui.Color{69, 39, 160}, ui.Color{69, 39, 160},
tui.Color{40, 53, 147}, ui.Color{40, 53, 147},
tui.Color{21, 101, 192}, ui.Color{21, 101, 192},
tui.Color{2, 119, 189}, ui.Color{2, 119, 189},
tui.Color{0, 131, 143}, ui.Color{0, 131, 143},
tui.Color{0, 105, 92}, ui.Color{0, 105, 92},
tui.Color{46, 125, 50}, ui.Color{46, 125, 50},
tui.Color{85, 139, 47}, ui.Color{85, 139, 47},
tui.Color{158, 157, 36}, ui.Color{158, 157, 36},
tui.Color{249, 168, 37}, ui.Color{249, 168, 37},
tui.Color{255, 143, 0}, ui.Color{255, 143, 0},
tui.Color{239, 108, 0}, ui.Color{239, 108, 0},
tui.Color{216, 67, 21}, ui.Color{216, 67, 21},
tui.Color{78, 52, 46}, ui.Color{78, 52, 46},
tui.Color{33, 33, 33}, ui.Color{33, 33, 33},
tui.Color{55, 71, 79}, ui.Color{55, 71, 79},
], ],
] ]
) )
@ -90,17 +90,17 @@ const (
struct App { struct App {
mut: mut:
tui &tui.Context = 0 ui &ui.Context = 0
header_text []string header_text []string
mouse_pos Point mouse_pos Point
msg string msg string
msg_hide_tick int msg_hide_tick int
primary_color tui.Color = colors[1][6] primary_color ui.Color = colors[1][6]
secondary_color tui.Color = colors[1][9] secondary_color ui.Color = colors[1][9]
primary_color_idx int = 25 primary_color_idx int = 25
secondary_color_idx int = 28 secondary_color_idx int = 28
bg_color tui.Color = tui.Color{0, 0, 0} bg_color ui.Color = ui.Color{0, 0, 0}
drawing [][]tui.Color = [][]tui.Color{len: h, init: []tui.Color{len: w}} drawing [][]ui.Color = [][]ui.Color{len: h, init: []ui.Color{len: w}}
size int = 1 size int = 1
should_redraw bool = true should_redraw bool = true
is_dragging bool is_dragging bool
@ -114,24 +114,24 @@ mut:
fn main() { fn main() {
mut app := &App{} mut app := &App{}
app.tui = tui.init({ app.ui = ui.init(
user_data: app user_data: app
frame_fn: frame frame_fn: frame
event_fn: event event_fn: event
frame_rate: frame_rate frame_rate: frame_rate
hide_cursor: true hide_cursor: true
window_title: 'V terminal pixelart drawing app' window_title: 'V terminal pixelart drawing app'
}) )
app.mouse_pos.x = 40 app.mouse_pos.x = 40
app.mouse_pos.y = 15 app.mouse_pos.y = 15
app.tui.clear() app.ui.clear()
app.tui.run() app.ui.run() ?
} }
fn frame(x voidptr) { fn frame(x voidptr) {
mut app := &App(x) mut app := &App(x)
mut redraw := app.should_redraw mut redraw := app.should_redraw
if app.msg != '' && app.tui.frame_count >= app.msg_hide_tick { if app.msg != '' && app.ui.frame_count >= app.msg_hide_tick {
app.msg = '' app.msg = ''
redraw = true redraw = true
} }
@ -141,12 +141,12 @@ fn frame(x voidptr) {
} }
} }
fn event(event &tui.Event, x voidptr) { fn event(event &ui.Event, x voidptr) {
mut app := &App(x) mut app := &App(x)
match event.typ { match event.typ {
.mouse_down { .mouse_down {
app.is_dragging = true app.is_dragging = true
if app.tui.window_height - event.y < 5 { if app.ui.window_height - event.y < 5 {
app.footer_click(event) app.footer_click(event)
} else { } else {
app.paint(event) app.paint(event)
@ -174,8 +174,8 @@ fn event(event &tui.Event, x voidptr) {
y: event.y y: event.y
} }
d := event.direction == .down d := event.direction == .down
if event.modifiers & tui.ctrl != 0 { if event.modifiers & ui.ctrl != 0 {
p := event.modifiers & tui.shift == 0 p := event.modifiers & ui.shift == 0
c := if d { c := if d {
if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 } if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 }
} else { } else {
@ -183,53 +183,72 @@ fn event(event &tui.Event, x voidptr) {
} }
app.select_color(p, c) app.select_color(p, c)
} else { } else {
if d { app.inc_size() } else { app.dec_size() } if d {
app.inc_size()
} else {
app.dec_size()
}
} }
} }
.key_down { .key_down {
match event.code { match event.code {
.f1, ._1 { .f1, ._1 {
oevent := *event oevent := *event
nevent := tui.Event{ ...oevent, button: tui.MouseButton.left, x: app.mouse_pos.x , y: app.mouse_pos.y } nevent := ui.Event{
...oevent
button: ui.MouseButton.left
x: app.mouse_pos.x
y: app.mouse_pos.y
}
app.paint(nevent) app.paint(nevent)
} }
.f2, ._2 { .f2, ._2 {
oevent := *event oevent := *event
nevent := tui.Event{ ...oevent, button: tui.MouseButton.right, x: app.mouse_pos.x , y: app.mouse_pos.y } nevent := ui.Event{
...oevent
button: ui.MouseButton.right
x: app.mouse_pos.x
y: app.mouse_pos.y
}
app.paint(nevent) app.paint(nevent)
} }
.space { .space {
oevent := *event oevent := *event
nevent := tui.Event{ ...oevent, button: tui.MouseButton.middle, x: app.mouse_pos.x , y: app.mouse_pos.y } nevent := ui.Event{
...oevent
button: ui.MouseButton.middle
x: app.mouse_pos.x
y: app.mouse_pos.y
}
app.paint(nevent) app.paint(nevent)
} }
.j, .down { .j, .down {
if event.modifiers & tui.shift != 0 { if event.modifiers & ui.shift != 0 {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
} }
app.mouse_pos.y++ app.mouse_pos.y++
} }
.k, .up { .k, .up {
if event.modifiers & tui.shift != 0 { if event.modifiers & ui.shift != 0 {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
} }
app.mouse_pos.y-- app.mouse_pos.y--
} }
.h, .left { .h, .left {
if event.modifiers & tui.shift != 0 { if event.modifiers & ui.shift != 0 {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
} }
app.mouse_pos.x -= 2 app.mouse_pos.x -= 2
} }
.l, .right { .l, .right {
if event.modifiers & tui.shift != 0 { if event.modifiers & ui.shift != 0 {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
} }
app.mouse_pos.x += 2 app.mouse_pos.x += 2
} }
.t { .t {
p := event.modifiers & tui.alt == 0 p := event.modifiers & ui.alt == 0
c := if event.modifiers & tui.shift != 0 { c := if event.modifiers & ui.shift != 0 {
if p { app.primary_color_idx - 19 } else { app.secondary_color_idx - 19 } if p { app.primary_color_idx - 19 } else { app.secondary_color_idx - 19 }
} else { } else {
if p { app.primary_color_idx + 19 } else { app.secondary_color_idx + 19 } if p { app.primary_color_idx + 19 } else { app.secondary_color_idx + 19 }
@ -237,8 +256,8 @@ fn event(event &tui.Event, x voidptr) {
app.select_color(p, c) app.select_color(p, c)
} }
.r { .r {
p := event.modifiers & tui.alt == 0 p := event.modifiers & ui.alt == 0
c := if event.modifiers & tui.shift != 0 { c := if event.modifiers & ui.shift != 0 {
if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 } if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 }
} else { } else {
if p { app.primary_color_idx + 1 } else { app.secondary_color_idx + 1 } if p { app.primary_color_idx + 1 } else { app.secondary_color_idx + 1 }
@ -252,7 +271,7 @@ fn event(event &tui.Event, x voidptr) {
app.dec_size() app.dec_size()
} }
.c { .c {
app.drawing = [][]tui.Color{len: h, init: []tui.Color{len: w}} app.drawing = [][]ui.Color{len: h, init: []ui.Color{len: w}}
} }
.q, .escape { .q, .escape {
app.render(true) app.render(true)
@ -267,14 +286,14 @@ fn event(event &tui.Event, x voidptr) {
} }
fn (mut app App) render(paint_only bool) { fn (mut app App) render(paint_only bool) {
app.tui.clear() app.ui.clear()
app.draw_header() app.draw_header()
app.draw_content() app.draw_content()
if !paint_only { if !paint_only {
app.draw_footer() app.draw_footer()
app.draw_cursor() app.draw_cursor()
} }
app.tui.flush() app.ui.flush()
} }
fn (mut app App) select_color(primary bool, idx int) { fn (mut app App) select_color(primary bool, idx int) {
@ -293,10 +312,10 @@ fn (mut app App) select_color(primary bool, idx int) {
app.show_msg('set $c_str color idx: $idx', 1) app.show_msg('set $c_str color idx: $idx', 1)
} }
fn (mut app App) set_pixel(x_ int, y_ int, c tui.Color) { fn (mut app App) set_pixel(x_ int, y_ int, c ui.Color) {
// Term coords start at 1, and adjust for the header // Term coords start at 1, and adjust for the header
x, y := x_ - 1, y_ - 4 x, y := x_ - 1, y_ - 4
if y < 0 || app.tui.window_height - y < 3 { if y < 0 || app.ui.window_height - y < 3 {
return return
} }
if y >= app.drawing.len || x < 0 || x >= app.drawing[0].len { if y >= app.drawing.len || x < 0 || x >= app.drawing[0].len {
@ -305,8 +324,8 @@ fn (mut app App) set_pixel(x_ int, y_ int, c tui.Color) {
app.drawing[y][x] = c app.drawing[y][x] = c
} }
fn (mut app App) paint(event &tui.Event) { fn (mut app App) paint(event &ui.Event) {
if event.y < 4 || app.tui.window_height - event.y < 4 { if event.y < 4 || app.ui.window_height - event.y < 4 {
return return
} }
x_start, y_start := int(f32((event.x - 1) / 2) - app.size / 2 + 1), event.y - app.size / 2 x_start, y_start := int(f32((event.x - 1) / 2) - app.size / 2 + 1), event.y - app.size / 2
@ -323,38 +342,38 @@ fn (mut app App) paint(event &tui.Event) {
} }
fn (mut app App) draw_content() { fn (mut app App) draw_content() {
w_, mut h_ := app.tui.window_width / 2, app.tui.window_height - 8 w_, mut h_ := app.ui.window_width / 2, app.ui.window_height - 8
if h_ > app.drawing.len { if h_ > app.drawing.len {
h_ = app.drawing.len h_ = app.drawing.len
} }
for row_idx, row in app.drawing[..h_] { for row_idx, row in app.drawing[..h_] {
app.tui.set_cursor_position(0, row_idx + 4) app.ui.set_cursor_position(0, row_idx + 4)
mut last := tui.Color{0, 0, 0} mut last := ui.Color{0, 0, 0}
for cell in row[..w_] { for cell in row[..w_] {
if cell.r == 0 && cell.g == 0 && cell.b == 0 { if cell.r == 0 && cell.g == 0 && cell.b == 0 {
if !(cell.r == last.r && cell.g == last.g && cell.b == last.b) { if !(cell.r == last.r && cell.g == last.g && cell.b == last.b) {
app.tui.reset() app.ui.reset()
} }
} else { } else {
if !(cell.r == last.r && cell.g == last.g && cell.b == last.b) { if !(cell.r == last.r && cell.g == last.g && cell.b == last.b) {
app.tui.set_bg_color(cell) app.ui.set_bg_color(cell)
} }
} }
app.tui.write(spaces) app.ui.write(spaces)
last = cell last = cell
} }
app.tui.reset() app.ui.reset()
} }
} }
fn (mut app App) draw_cursor() { fn (mut app App) draw_cursor() {
if app.mouse_pos.y in [3, app.tui.window_height - 5] { if app.mouse_pos.y in [3, app.ui.window_height - 5] {
// inside the horizontal separators // inside the horizontal separators
return return
} }
cursor_color := if app.is_dragging { tui.Color{220, 220, 220} } else { tui.Color{160, 160, 160} } cursor_color := if app.is_dragging { ui.Color{220, 220, 220} } else { ui.Color{160, 160, 160} }
app.tui.set_bg_color(cursor_color) app.ui.set_bg_color(cursor_color)
if app.mouse_pos.y >= 3 && app.mouse_pos.y <= app.tui.window_height - 4 { if app.mouse_pos.y >= 3 && app.mouse_pos.y <= app.ui.window_height - 4 {
// inside the main content // inside the main content
mut x_start := int(f32((app.mouse_pos.x - 1) / 2) - app.size / 2 + 1) * 2 - 1 mut x_start := int(f32((app.mouse_pos.x - 1) / 2) - app.size / 2 + 1) * 2 - 1
mut y_start := app.mouse_pos.y - app.size / 2 mut y_start := app.mouse_pos.y - app.size / 2
@ -366,70 +385,71 @@ fn (mut app App) draw_cursor() {
if y_start < 4 { if y_start < 4 {
y_start = 4 y_start = 4
} }
if x_end > app.tui.window_width { if x_end > app.ui.window_width {
x_end = app.tui.window_width x_end = app.ui.window_width
} }
if y_end > app.tui.window_height - 5 { if y_end > app.ui.window_height - 5 {
y_end = app.tui.window_height - 5 y_end = app.ui.window_height - 5
} }
app.tui.draw_rect(x_start, y_start, x_end, y_end) app.ui.draw_rect(x_start, y_start, x_end, y_end)
} else { } else {
app.tui.draw_text(app.mouse_pos.x, app.mouse_pos.y, space) app.ui.draw_text(app.mouse_pos.x, app.mouse_pos.y, space)
} }
app.tui.reset() app.ui.reset()
} }
fn (mut app App) draw_header() { fn (mut app App) draw_header() {
if app.msg != '' { if app.msg != '' {
app.tui.set_color({ app.ui.set_color(
r: 0 r: 0
g: 0 g: 0
b: 0 b: 0
}) )
app.tui.set_bg_color({ app.ui.set_bg_color(
r: 220 r: 220
g: 220 g: 220
b: 220 b: 220
}) )
app.tui.draw_text(0, 0, ' $app.msg ') app.ui.draw_text(0, 0, ' $app.msg ')
app.tui.reset() app.ui.reset()
} }
app.tui.draw_text(3, 2, /* 'tick: $app.tui.frame_count | ' + */ 'terminal size: ($app.tui.window_width, $app.tui.window_height) | primary color: $app.primary_color.hex() | secondary color: $app.secondary_color.hex()') //'tick: $app.ui.frame_count | ' +
app.tui.horizontal_separator(3) app.ui.draw_text(3, 2, 'terminal size: ($app.ui.window_width, $app.ui.window_height) | primary color: $app.primary_color.hex() | secondary color: $app.secondary_color.hex()')
app.ui.horizontal_separator(3)
} }
fn (mut app App) draw_footer() { fn (mut app App) draw_footer() {
_, wh := app.tui.window_width, app.tui.window_height _, wh := app.ui.window_width, app.ui.window_height
app.tui.horizontal_separator(wh - 4) app.ui.horizontal_separator(wh - 4)
for i, color_row in colors { for i, color_row in colors {
for j, color in color_row { for j, color in color_row {
x := j * 3 + 19 x := j * 3 + 19
y := wh - 3 + i y := wh - 3 + i
app.tui.set_bg_color(color) app.ui.set_bg_color(color)
if app.primary_color_idx == j + (i * 19) { if app.primary_color_idx == j + (i * 19) {
app.tui.set_color(r: 0, g: 0, b: 0) app.ui.set_color(r: 0, g: 0, b: 0)
app.tui.draw_text(x, y, '><') app.ui.draw_text(x, y, '><')
app.tui.reset_color() app.ui.reset_color()
} else if app.secondary_color_idx == j + (i * 19) { } else if app.secondary_color_idx == j + (i * 19) {
app.tui.set_color(r: 255, g: 255, b: 255) app.ui.set_color(r: 255, g: 255, b: 255)
app.tui.draw_text(x, y, '><') app.ui.draw_text(x, y, '><')
app.tui.reset_color() app.ui.reset_color()
} else { } else {
app.tui.draw_rect(x, y, x + 1, y) app.ui.draw_rect(x, y, x + 1, y)
} }
} }
} }
app.tui.reset_bg_color() app.ui.reset_bg_color()
app.tui.draw_text(3, wh - 3, select_color) app.ui.draw_text(3, wh - 3, select_color)
app.tui.bold() app.ui.bold()
app.tui.draw_text(3, wh - 1, '$select_size $app.size') app.ui.draw_text(3, wh - 1, '$select_size $app.size')
app.tui.reset() app.ui.reset()
// TODO: help button // TODO: help button
// if ww >= 90 { // if ww >= 90 {
// app.tui.draw_text(80, wh - 3, help_1) // app.ui.draw_text(80, wh - 3, help_1)
// app.tui.draw_text(80, wh - 2, help_2) // app.ui.draw_text(80, wh - 2, help_2)
// app.tui.draw_text(80, wh - 1, help_3) // app.ui.draw_text(80, wh - 1, help_3)
// } // }
} }
@ -449,8 +469,8 @@ fn (mut app App) dec_size() {
app.show_msg('dec. size: $app.size', 1) app.show_msg('dec. size: $app.size', 1)
} }
fn (mut app App) footer_click(event &tui.Event) { fn (mut app App) footer_click(event &ui.Event) {
footer_y := 3 - (app.tui.window_height - event.y) footer_y := 3 - (app.ui.window_height - event.y)
match event.x { match event.x {
8...11 { 8...11 {
app.inc_size() app.inc_size()
@ -464,7 +484,9 @@ fn (mut app App) footer_click(event &tui.Event) {
return return
} }
idx := footer_y * 19 - 6 + event.x / 3 idx := footer_y * 19 - 6 + event.x / 3
if idx < 0 || idx > 56 { return } if idx < 0 || idx > 56 {
return
}
app.select_color(event.button == .left, idx) app.select_color(event.button == .left, idx)
} }
else {} else {}
@ -473,6 +495,6 @@ fn (mut app App) footer_click(event &tui.Event) {
fn (mut app App) show_msg(text string, time int) { fn (mut app App) show_msg(text string, time int) {
frames := time * frame_rate frames := time * frame_rate
app.msg_hide_tick = if time > 0 { int(app.tui.frame_count) + frames } else { -1 } app.msg_hide_tick = if time > 0 { int(app.ui.frame_count) + frames } else { -1 }
app.msg = text app.msg = text
} }

View File

@ -44,7 +44,7 @@ fn (mut a App) set_status(msg string, duration_ms int) {
fn (mut a App) save() { fn (mut a App) save() {
if a.cfile().len > 0 { if a.cfile().len > 0 {
b := a.ed b := a.ed
os.write_file(a.cfile(), b.raw()) os.write_file(a.cfile(), b.raw()) or { panic(err) }
a.set_status('Saved', 2000) a.set_status('Saved', 2000)
} else { } else {
a.set_status('No file loaded', 4000) a.set_status('No file loaded', 4000)
@ -79,7 +79,6 @@ fn (mut a App) visit_next_file() {
a.init_file() a.init_file()
} }
fn (mut a App) footer() { fn (mut a App) footer() {
w, h := a.tui.window_width, a.tui.window_height w, h := a.tui.window_width, a.tui.window_height
mut b := a.ed mut b := a.ed
@ -99,16 +98,16 @@ fn (mut a App) footer() {
if a.t <= 0 { if a.t <= 0 {
status = '' status = ''
} else { } else {
a.tui.set_bg_color({ a.tui.set_bg_color(
r: 200 r: 200
g: 200 g: 200
b: 200 b: 200
}) )
a.tui.set_color({ a.tui.set_color(
r: 0 r: 0
g: 0 g: 0
b: 0 b: 0
}) )
a.tui.draw_text((w + 4 - status.len) / 2, h - 1, ' $status ') a.tui.draw_text((w + 4 - status.len) / 2, h - 1, ' $status ')
a.tui.reset() a.tui.reset()
a.t -= 33 a.t -= 33
@ -374,9 +373,15 @@ fn (mut b Buffer) move_to_word(movement Movement) {
x = 0 x = 0
} }
// first, move past all non-`a-zA-Z0-9_` characters // first, move past all non-`a-zA-Z0-9_` characters
for x+a >= 0 && x+a < line.len && !(line[x+a].is_letter() || line[x+a].is_digit() || line[x+a] == `_`) { x += a } for x + a >= 0 && x + a < line.len && !(line[x + a].is_letter()
|| line[x + a].is_digit()|| line[x + a] == `_`) {
x += a
}
// then, move past all the letters and numbers // then, move past all the letters and numbers
for x+a >= 0 && x+a < line.len && (line[x+a].is_letter() || line[x+a].is_digit() || line[x+a] == `_`) { x += a } for x + a >= 0 && x + a < line.len && (line[x + a].is_letter()
|| line[x + a].is_digit()|| line[x + a] == `_`) {
x += a
}
// if the cursor is out of bounds, move it to the next/previous line // if the cursor is out of bounds, move it to the next/previous line
if x + a >= 0 && x + a <= line.len { if x + a >= 0 && x + a <= line.len {
x += a x += a
@ -388,11 +393,19 @@ fn (mut b Buffer) move_to_word(movement Movement) {
} }
fn imax(x int, y int) int { fn imax(x int, y int) int {
return if x < y { y } else { x } return if x < y {
y
} else {
x
}
} }
fn imin(x int, y int) int { fn imin(x int, y int) int {
return if x < y { x } else { y } return if x < y {
x
} else {
y
}
} }
struct Cursor { struct Cursor {
@ -443,9 +456,7 @@ fn (mut a App) init_file() {
// 'vico: ' + // 'vico: ' +
a.tui.set_window_title(a.files[a.current_file]) a.tui.set_window_title(a.files[a.current_file])
mut b := a.ed mut b := a.ed
content := os.read_file(a.files[a.current_file]) or { content := os.read_file(a.files[a.current_file]) or { panic(err) }
panic(err)
}
b.put(content) b.put(content)
a.ed.cursor.pos_x = init_x a.ed.cursor.pos_x = init_x
a.ed.cursor.pos_y = init_y a.ed.cursor.pos_y = init_y
@ -573,12 +584,12 @@ fn main() {
mut a := &App{ mut a := &App{
files: files files: files
} }
a.tui = tui.init({ a.tui = tui.init(
user_data: a user_data: a
init_fn: init init_fn: init
frame_fn: frame frame_fn: frame
event_fn: event event_fn: event
capture_events: true capture_events: true
}) )
a.tui.run() a.tui.run() ?
} }

View File

@ -125,8 +125,16 @@ fn (mut s Snake) move() {
piece.facing = s.direction piece.facing = s.direction
new_x := piece.pos.x + s.velocity.x new_x := piece.pos.x + s.velocity.x
new_y := piece.pos.y + s.velocity.y new_y := piece.pos.y + s.velocity.y
piece.pos.x += if new_x > block_size && new_x < width - block_size { s.velocity.x } else { 0 } piece.pos.x += if new_x > block_size && new_x < width - block_size {
piece.pos.y += if new_y > block_size && new_y < height - block_size { s.velocity.y } else { 0 } s.velocity.x
} else {
0
}
piece.pos.y += if new_y > block_size && new_y < height - block_size {
s.velocity.y
} else {
0
}
} }
s.body[i] = piece s.body[i] = piece
} }
@ -205,10 +213,10 @@ fn (s Snake) check_overlap() bool {
fn (s Snake) check_out_of_bounds() bool { fn (s Snake) check_out_of_bounds() bool {
h := s.get_head() h := s.get_head()
return h.pos.x + s.velocity.x <= block_size || return h.pos.x + s.velocity.x <= block_size
h.pos.x + s.velocity.x > s.app.width - s.velocity.x || h.pos.y + s.velocity.y <= block_size || || h.pos.x + s.velocity.x > s.app.width - s.velocity.x
h.pos.y + s.velocity.y > || h.pos.y + s.velocity.y <= block_size
s.app.height - block_size - s.velocity.y || h.pos.y + s.velocity.y > s.app.height - block_size - s.velocity.y
} }
// draw draws the parts of the snake // draw draws the parts of the snake
@ -244,8 +252,8 @@ mut:
// randomize spawn the rat in a new spot within the playable field // randomize spawn the rat in a new spot within the playable field
fn (mut r Rat) randomize() { fn (mut r Rat) randomize() {
r.pos.randomize(2 * block_size + buffer, 2 * block_size + buffer, r.app.width - block_size - r.pos.randomize(2 * block_size + buffer, 2 * block_size + buffer, r.app.width - block_size - buffer,
buffer, r.app.height - block_size - buffer) r.app.height - block_size - buffer)
} }
struct App { struct App {
@ -387,9 +395,8 @@ fn (mut a App) move_snake(direction Orientation) {
fn (a App) check_capture() bool { fn (a App) check_capture() bool {
snake_pos := a.snake.get_head().pos snake_pos := a.snake.get_head().pos
rat_pos := a.rat.pos rat_pos := a.rat.pos
return snake_pos.x <= rat_pos.x + block_size && return snake_pos.x <= rat_pos.x + block_size && snake_pos.x + block_size >= rat_pos.x
snake_pos.x + block_size >= rat_pos.x && snake_pos.y <= rat_pos.y + block_size && snake_pos.y + && snake_pos.y <= rat_pos.y + block_size&& snake_pos.y + block_size >= rat_pos.y
block_size >= rat_pos.y
} }
fn (mut a App) draw_snake() { fn (mut a App) draw_snake() {
@ -454,12 +461,12 @@ fn (mut a App) draw_gameover() {
} }
mut app := &App{} mut app := &App{}
app.termui = termui.init({ app.termui = termui.init(
user_data: app user_data: app
event_fn: event event_fn: event
frame_fn: frame frame_fn: frame
init_fn: init init_fn: init
hide_cursor: true hide_cursor: true
frame_rate: 10 frame_rate: 10
}) )
app.termui.run() app.termui.run() ?

View File

@ -16,11 +16,9 @@ fn main() {
if line == '' { if line == '' {
break break
} }
ws.write_str(line) ws.write_str(line) ?
}
ws.close(1000, 'normal') or {
println(term.red('panicing $err'))
} }
ws.close(1000, 'normal') or { println(term.red('panicing $err')) }
unsafe { unsafe {
ws.free() ws.free()
} }
@ -49,12 +47,8 @@ fn start_client() ?&websocket.Client {
} }
}) })
ws.connect() or { ws.connect() or { println(term.red('error on connect: $err')) }
println(term.red('error on connect: $err'))
}
go ws.listen() or { go ws.listen() or { println(term.red('error on listen $err')) }
println(term.red('error on listen $err'))
}
return ws return ws
} }

View File

@ -259,7 +259,7 @@ fn (cmd Command) check_version_flag() {
version_flag := cmd.flags.get_bool('version') or { return } // ignore error and handle command normally version_flag := cmd.flags.get_bool('version') or { return } // ignore error and handle command normally
if version_flag { if version_flag {
version_cmd := cmd.commands.get('version') or { return } // ignore error and handle command normally version_cmd := cmd.commands.get('version') or { return } // ignore error and handle command normally
version_cmd.execute(version_cmd) version_cmd.execute(version_cmd) or { panic(err) }
exit(0) exit(0)
} }
} }
@ -280,7 +280,7 @@ fn (cmd Command) check_required_flags() {
pub fn (cmd Command) execute_help() { pub fn (cmd Command) execute_help() {
if cmd.commands.contains('help') { if cmd.commands.contains('help') {
help_cmd := cmd.commands.get('help') or { return } // ignore error and handle command normally help_cmd := cmd.commands.get('help') or { return } // ignore error and handle command normally
help_cmd.execute(help_cmd) help_cmd.execute(help_cmd) or { panic(err) }
} else { } else {
print(cmd.help_message()) print(cmd.help_message())
} }

View File

@ -22,7 +22,7 @@ fn test_vexe() {
fn test_can_compile_library() { fn test_can_compile_library() {
os.chdir(cfolder) os.chdir(cfolder)
os.rm(library_file_name) os.rm(library_file_name) or { }
res := v_compile('-d no_backtrace -o library -shared library.v') res := v_compile('-d no_backtrace -o library -shared library.v')
eprintln('res: $res') eprintln('res: $res')
assert os.is_file(library_file_name) assert os.is_file(library_file_name)
@ -34,7 +34,7 @@ fn test_can_compile_main_program() {
result := v_compile('run use.v') result := v_compile('run use.v')
eprintln('result: $result') eprintln('result: $result')
assert result.output.contains('res: 4') assert result.output.contains('res: 4')
os.rm(library_file_name) os.rm(library_file_name) or { }
} }
fn v_compile(vopts string) os.Result { fn v_compile(vopts string) os.Result {

View File

@ -10,16 +10,16 @@ const (
fn testsuite_begin() { fn testsuite_begin() {
eprintln('testsuite_begin, tfolder = $tfolder') eprintln('testsuite_begin, tfolder = $tfolder')
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
os.mkdir_all(tfolder) os.mkdir_all(tfolder) or { panic(err) }
os.chdir(tfolder) os.chdir(tfolder)
assert os.is_dir(tfolder) assert os.is_dir(tfolder)
} }
fn testsuite_end() { fn testsuite_end() {
os.chdir(os.wd_at_startup) os.chdir(os.wd_at_startup)
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
// eprintln('testsuite_end , tfolder = $tfolder removed.') // eprintln('testsuite_end , tfolder = $tfolder removed.')
} }
@ -38,9 +38,9 @@ fn test_temp_file() {
assert f.is_opened assert f.is_opened
// Test pattern // Test pattern
f.close() f.close()
f, path = util.temp_file({ f, path = util.temp_file(
pattern: 'some_*_test.file' pattern: 'some_*_test.file'
}) or { ) or {
assert false assert false
return return
} }
@ -58,9 +58,9 @@ fn test_temp_file() {
// Test custom path // Test custom path
prev_path = path prev_path = path
f.close() f.close()
f, path = util.temp_file({ f, path = util.temp_file(
path: tfolder path: tfolder
}) or { ) or {
assert false assert false
return return
} }
@ -88,9 +88,9 @@ fn test_temp_dir() {
assert writable assert writable
mut prev_path := path mut prev_path := path
// Test pattern // Test pattern
path = util.temp_dir({ path = util.temp_dir(
pattern: 'some_*_test_dir' pattern: 'some_*_test_dir'
}) or { ) or {
assert false assert false
return return
} }
@ -106,9 +106,9 @@ fn test_temp_dir() {
} }
// Test custom path // Test custom path
prev_path = path prev_path = path
path = util.temp_dir({ path = util.temp_dir(
path: tfolder path: tfolder
}) or { ) or {
assert false assert false
return return
} }

View File

@ -106,7 +106,7 @@ pub fn (mut l Log) close() {
fn (mut l Log) log_file(s string, level Level) { fn (mut l Log) log_file(s string, level Level) {
timestamp := time.now().format_ss() timestamp := time.now().format_ss()
e := tag_to_file(level) e := tag_to_file(level)
l.ofile.writeln('$timestamp [$e] $s') l.ofile.writeln('$timestamp [$e] $s') or { panic(err) }
} }
// log_cli writes log line `s` with `level` to stdout. // log_cli writes log line `s` with `level` to stdout.

View File

@ -36,7 +36,7 @@ pub fn socket_error(potential_code int) ?int {
pub fn wrap_error(error_code int) ? { pub fn wrap_error(error_code int) ? {
$if windows { $if windows {
enum_error := wsa_error(error_code) enum_error := wsa_error(error_code)
return error_with_code('socket error: $enum_error', error_code) return error_with_code('net: socket error: $enum_error', error_code)
} }
$else { $else {
if error_code == 0 { if error_code == 0 {

View File

@ -36,7 +36,7 @@ const (
struct DTP { struct DTP {
mut: mut:
conn net.TcpConn conn &net.TcpConn
reader io.BufferedReader reader io.BufferedReader
ip string ip string
port int port int
@ -56,31 +56,31 @@ fn (mut dtp DTP) read() ?[]byte {
} }
fn (mut dtp DTP) close() { fn (mut dtp DTP) close() {
dtp.conn.close() dtp.conn.close() or { panic(err) }
} }
struct FTP { struct FTP {
mut: mut:
conn net.TcpConn conn &net.TcpConn
reader io.BufferedReader reader io.BufferedReader
buffer_size int buffer_size int
} }
pub fn new() FTP { pub fn new() FTP {
mut f := FTP{} mut f := FTP{ conn: 0 }
f.buffer_size = 1024 f.buffer_size = 1024
return f return f
} }
fn (mut ftp FTP) write(data string) ? { fn (mut zftp FTP) write(data string) ? {
$if debug { $if debug {
println('FTP.v >>> $data') println('FTP.v >>> $data')
} }
ftp.conn.write('$data\r\n'.bytes()) ? zftp.conn.write('$data\r\n'.bytes()) ?
} }
fn (mut ftp FTP) read() ?(int, string) { fn (mut zftp FTP) read() ?(int, string) {
mut data := ftp.reader.read_line() ? mut data := zftp.reader.read_line() ?
$if debug { $if debug {
println('FTP.v <<< $data') println('FTP.v <<< $data')
} }
@ -90,7 +90,7 @@ fn (mut ftp FTP) read() ?(int, string) {
code := data[..3].int() code := data[..3].int()
if data[3] == `-` { if data[3] == `-` {
for { for {
data = ftp.reader.read_line() ? data = zftp.reader.read_line() ?
if data[..3].int() == code && data[3] != `-` { if data[..3].int() == code && data[3] != `-` {
break break
} }
@ -99,51 +99,51 @@ fn (mut ftp FTP) read() ?(int, string) {
return code, data return code, data
} }
pub fn (mut ftp FTP) connect(ip string) ?bool { pub fn (mut zftp FTP) connect(ip string) ?bool {
ftp.conn = net.dial_tcp('$ip:21') ? zftp.conn = net.dial_tcp('$ip:21') ?
ftp.reader = io.new_buffered_reader(reader: io.make_reader(ftp.conn)) zftp.reader = io.new_buffered_reader(reader: io.make_reader(zftp.conn))
code, _ := ftp.read() ? code, _ := zftp.read() ?
if code == connected { if code == ftp.connected {
return true return true
} }
return false return false
} }
pub fn (mut ftp FTP) login(user string, passwd string) ?bool { pub fn (mut zftp FTP) login(user string, passwd string) ?bool {
ftp.write('USER $user') or { zftp.write('USER $user') or {
$if debug { $if debug {
println('ERROR sending user') println('ERROR sending user')
} }
return false return false
} }
mut code, _ := ftp.read() ? mut code, _ := zftp.read() ?
if code == logged_in { if code == ftp.logged_in {
return true return true
} }
if code != specify_password { if code != ftp.specify_password {
return false return false
} }
ftp.write('PASS $passwd') or { zftp.write('PASS $passwd') or {
$if debug { $if debug {
println('ERROR sending password') println('ERROR sending password')
} }
return false return false
} }
code, _ = ftp.read() ? code, _ = zftp.read() ?
if code == logged_in { if code == ftp.logged_in {
return true return true
} }
return false return false
} }
pub fn (mut ftp FTP) close() ? { pub fn (mut zftp FTP) close() ? {
ftp.write('QUIT') ? zftp.write('QUIT') ?
ftp.conn.close() zftp.conn.close() ?
} }
pub fn (mut ftp FTP) pwd() ?string { pub fn (mut zftp FTP) pwd() ?string {
ftp.write('PWD') ? zftp.write('PWD') ?
_, data := ftp.read() ? _, data := zftp.read() ?
spl := data.split('"') // " spl := data.split('"') // "
if spl.len >= 2 { if spl.len >= 2 {
return spl[1] return spl[1]
@ -151,17 +151,17 @@ pub fn (mut ftp FTP) pwd() ?string {
return data return data
} }
pub fn (mut ftp FTP) cd(dir string) ? { pub fn (mut zftp FTP) cd(dir string) ? {
ftp.write('CWD $dir') or { return } zftp.write('CWD $dir') or { return }
mut code, mut data := ftp.read() ? mut code, mut data := zftp.read() ?
match int(code) { match int(code) {
denied { ftp.denied {
$if debug { $if debug {
println('CD $dir denied!') println('CD $dir denied!')
} }
} }
complete { ftp.complete {
code, data = ftp.read() ? code, data = zftp.read() ?
} }
else {} else {}
} }
@ -178,6 +178,7 @@ fn new_dtp(msg string) ?&DTP {
mut dtp := &DTP{ mut dtp := &DTP{
ip: ip ip: ip
port: port port: port
conn: 0
} }
conn := net.dial_tcp('$ip:$port') or { return error('Cannot connect to the data channel') } conn := net.dial_tcp('$ip:$port') or { return error('Cannot connect to the data channel') }
dtp.conn = conn dtp.conn = conn
@ -185,32 +186,32 @@ fn new_dtp(msg string) ?&DTP {
return dtp return dtp
} }
fn (mut ftp FTP) pasv() ?&DTP { fn (mut zftp FTP) pasv() ?&DTP {
ftp.write('PASV') ? zftp.write('PASV') ?
code, data := ftp.read() ? code, data := zftp.read() ?
$if debug { $if debug {
println('pass: $data') println('pass: $data')
} }
if code != passive_mode { if code != ftp.passive_mode {
return error('pasive mode not allowed') return error('pasive mode not allowed')
} }
dtp := new_dtp(data) ? dtp := new_dtp(data) ?
return dtp return dtp
} }
pub fn (mut ftp FTP) dir() ?[]string { pub fn (mut zftp FTP) dir() ?[]string {
mut dtp := ftp.pasv() or { return error('Cannot establish data connection') } mut dtp := zftp.pasv() or { return error('Cannot establish data connection') }
ftp.write('LIST') ? zftp.write('LIST') ?
code, _ := ftp.read() ? code, _ := zftp.read() ?
if code == denied { if code == ftp.denied {
return error('`LIST` denied') return error('`LIST` denied')
} }
if code != open_data_connection { if code != ftp.open_data_connection {
return error('Data channel empty') return error('Data channel empty')
} }
list_dir := dtp.read() ? list_dir := dtp.read() ?
result, _ := ftp.read() ? result, _ := zftp.read() ?
if result != close_data_connection { if result != ftp.close_data_connection {
println('`LIST` not ok') println('`LIST` not ok')
} }
dtp.close() dtp.close()
@ -225,14 +226,14 @@ pub fn (mut ftp FTP) dir() ?[]string {
return dir return dir
} }
pub fn (mut ftp FTP) get(file string) ?[]byte { pub fn (mut zftp FTP) get(file string) ?[]byte {
mut dtp := ftp.pasv() or { return error('Cannot stablish data connection') } mut dtp := zftp.pasv() or { return error('Cannot stablish data connection') }
ftp.write('RETR $file') ? zftp.write('RETR $file') ?
code, _ := ftp.read() ? code, _ := zftp.read() ?
if code == denied { if code == ftp.denied {
return error('Permission denied') return error('Permission denied')
} }
if code != open_data_connection { if code != ftp.open_data_connection {
return error('Data connection not ready') return error('Data connection not ready')
} }
blob := dtp.read() ? blob := dtp.read() ?

View File

@ -1,42 +1,49 @@
import net.ftp import net.ftp
fn test_ftp_cleint() {
$if !network ? {
return
}
// NB: this function makes network calls to external servers, // NB: this function makes network calls to external servers,
// that is why it is not a very good idea to run it in CI. // that is why it is not a very good idea to run it in CI.
// If you want to run it manually, use `v -d network vlib/net/ftp/ftp_test.v` // If you want to run it manually, use:
fn ftp_client_test_inside() ? { // `v -d network vlib/net/ftp/ftp_test.v`
$if !network ? { return } ftp_client_test_inside() or { panic(err) }
mut ftp := ftp.new()
defer {
ftp.close()
} }
connect_result := ftp.connect('ftp.redhat.com')?
fn ftp_client_test_inside() ? {
mut zftp := ftp.new()
// eprintln(zftp)
defer {
zftp.close() or { panic(err) }
}
connect_result := zftp.connect('ftp.redhat.com') ?
assert connect_result assert connect_result
login_result := ftp.login('ftp', 'ftp')? login_result := zftp.login('ftp', 'ftp') ?
assert login_result assert login_result
pwd := ftp.pwd()? pwd := zftp.pwd() ?
assert pwd.len > 0 assert pwd.len > 0
ftp.cd('/') zftp.cd('/') or {
dir_list1 := ftp.dir() or { assert false
return
}
dir_list1 := zftp.dir() or {
assert false assert false
return return
} }
assert dir_list1.len > 0 assert dir_list1.len > 0
ftp.cd('/suse/linux/enterprise/11Server/en/SAT-TOOLS/SRPMS/') zftp.cd('/suse/linux/enterprise/11Server/en/SAT-TOOLS/SRPMS/') or {
dir_list2 := ftp.dir() or { assert false
return
}
dir_list2 := zftp.dir() or {
assert false assert false
return return
} }
assert dir_list2.len > 0 assert dir_list2.len > 0
blob := ftp.get('katello-host-tools-3.3.5-8.sles11_4sat.src.rpm') or { blob := zftp.get('katello-host-tools-3.3.5-8.sles11_4sat.src.rpm') or {
assert false assert false
return return
} }
assert blob.len > 0 assert blob.len > 0
} }
fn test_ftp_cleint() {
ftp_client_test_inside() or {
panic(err)
}
}

View File

@ -9,9 +9,7 @@ pub fn download_file(url string, out string)? {
$if debug_http ? { $if debug_http ? {
println('download file url=$url out=$out') println('download file url=$url out=$out')
} }
s := get(url) or { s := get(url) or { return error(err) }
return error(err) os.write_file(out, s.text) ?
}
os.write_file(out, s.text)
// download_file_with_progress(url, out, empty, empty) // download_file_with_progress(url, out, empty, empty)
} }

View File

@ -67,33 +67,48 @@ pub fn get(url string) ?Response {
} }
pub fn post(url string, data string) ?Response { pub fn post(url string, data string) ?Response {
return fetch_with_method(.post, url, data: data, headers: { return fetch_with_method(.post, url,
'Content-Type': content_type_default data: data
}) headers: {
'Content-Type': http.content_type_default
}
)
} }
pub fn post_json(url string, data string) ?Response { pub fn post_json(url string, data string) ?Response {
return fetch_with_method(.post, url, data: data, headers: { return fetch_with_method(.post, url,
data: data
headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}) }
)
} }
pub fn post_form(url string, data map[string]string) ?Response { pub fn post_form(url string, data map[string]string) ?Response {
return fetch_with_method(.post, url, headers: { return fetch_with_method(.post, url,
headers: {
'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type': 'application/x-www-form-urlencoded'
}, data: url_encode_form_data(data)) }
data: url_encode_form_data(data)
)
} }
pub fn put(url string, data string) ?Response { pub fn put(url string, data string) ?Response {
return fetch_with_method(.put, url, data: data, headers: { return fetch_with_method(.put, url,
'Content-Type': content_type_default data: data
}) headers: {
'Content-Type': http.content_type_default
}
)
} }
pub fn patch(url string, data string) ?Response { pub fn patch(url string, data string) ?Response {
return fetch_with_method(.patch, url, data: data, headers: { return fetch_with_method(.patch, url,
'Content-Type': content_type_default data: data
}) headers: {
'Content-Type': http.content_type_default
}
)
} }
pub fn head(url string) ?Response { pub fn head(url string) ?Response {
@ -199,8 +214,8 @@ pub fn (req &Request) do() ?Response {
mut resp := Response{} mut resp := Response{}
mut no_redirects := 0 mut no_redirects := 0
for { for {
if no_redirects == max_redirects { if no_redirects == http.max_redirects {
return error('http.request.do: maximum number of redirects reached ($max_redirects)') return error('http.request.do: maximum number of redirects reached ($http.max_redirects)')
} }
qresp := req.method_and_url_to_response(req.method, rurl) ? qresp := req.method_and_url_to_response(req.method, rurl) ?
resp = qresp resp = qresp
@ -366,7 +381,7 @@ fn (req &Request) http_do(host string, method Method, path string) ?Response {
// TODO this really needs to be exposed somehow // TODO this really needs to be exposed somehow
client.write(s.bytes()) ? client.write(s.bytes()) ?
mut bytes := io.read_all(reader: client) ? mut bytes := io.read_all(reader: client) ?
client.close() client.close() ?
return parse_response(bytes.bytestr()) return parse_response(bytes.bytestr())
} }

View File

@ -96,8 +96,8 @@ pub fn (mut c Client) send(config Mail) ? {
// quit closes the connection to the server // quit closes the connection to the server
pub fn (mut c Client) quit() ? { pub fn (mut c Client) quit() ? {
c.send_str('QUIT\r\n') c.send_str('QUIT\r\n') ?
c.expect_reply(.close) c.expect_reply(.close) ?
c.conn.close() ? c.conn.close() ?
c.is_open = false c.is_open = false
} }
@ -166,7 +166,7 @@ fn (mut c Client) send_mailto(to string) ? {
fn (mut c Client) send_data() ? { fn (mut c Client) send_data() ? {
c.send_str('DATA\r\n') ? c.send_str('DATA\r\n') ?
c.expect_reply(.mail_start) c.expect_reply(.mail_start) ?
} }
fn (mut c Client) send_body(cfg Mail) ? { fn (mut c Client) send_body(cfg Mail) ? {

View File

@ -22,8 +22,8 @@ pub fn dial_tcp(address string) ?&TcpConn {
s.connect(address) ? s.connect(address) ?
return &TcpConn{ return &TcpConn{
sock: s sock: s
read_timeout: tcp_default_read_timeout read_timeout: net.tcp_default_read_timeout
write_timeout: tcp_default_write_timeout write_timeout: net.tcp_default_write_timeout
} }
} }
@ -35,7 +35,8 @@ pub fn (mut c TcpConn) close() ? {
// write_ptr blocks and attempts to write all data // write_ptr blocks and attempts to write all data
pub fn (mut c TcpConn) write_ptr(b byteptr, len int) ? { pub fn (mut c TcpConn) write_ptr(b byteptr, len int) ? {
$if trace_tcp ? { $if trace_tcp ? {
eprintln('>>> TcpConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' + eprintln(
'>>> TcpConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' +
unsafe { b.vstring_with_len(len) }) unsafe { b.vstring_with_len(len) })
} }
unsafe { unsafe {
@ -48,7 +49,7 @@ pub fn (mut c TcpConn) write_ptr(b byteptr, len int) ? {
if sent < 0 { if sent < 0 {
code := error_code() code := error_code()
if code == int(error_ewouldblock) { if code == int(error_ewouldblock) {
c.wait_for_write() c.wait_for_write() ?
continue continue
} else { } else {
wrap_error(code) ? wrap_error(code) ?
@ -164,9 +165,9 @@ pub fn (c &TcpConn) peer_ip() ?string {
return res return res
} }
pub fn (c &TcpConn) str() string { pub fn (c TcpConn) str() string {
// TODO s := c.sock.str().replace('\n', ' ').replace(' ', ' ')
return 'TcpConn {write_deadline: $c.write_deadline, read_deadline: $c.read_deadline, read_timeout: $c.read_timeout, write_timeout: $c.write_timeout, sock: $c.sock}' return 'TcpConn{ write_deadline: $c.write_deadline, read_deadline: $c.read_deadline, read_timeout: $c.read_timeout, write_timeout: $c.write_timeout, sock: $s }'
} }
pub struct TcpListener { pub struct TcpListener {
@ -213,8 +214,8 @@ pub fn (mut l TcpListener) accept() ?&TcpConn {
new_sock := tcp_socket_from_handle(new_handle) ? new_sock := tcp_socket_from_handle(new_handle) ?
return &TcpConn{ return &TcpConn{
sock: new_sock sock: new_sock
read_timeout: tcp_default_read_timeout read_timeout: net.tcp_default_read_timeout
write_timeout: tcp_default_write_timeout write_timeout: net.tcp_default_write_timeout
} }
} }
@ -266,7 +267,7 @@ fn new_tcp_socket() ?TcpSocket {
t := true t := true
socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ? socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ?
} $else { } $else {
socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK)) socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK)) ?
} }
return s return s
} }
@ -281,7 +282,7 @@ fn tcp_socket_from_handle(sockfd int) ?TcpSocket {
t := true t := true
socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ? socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ?
} $else { } $else {
socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK)) socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK)) ?
} }
return s return s
} }
@ -322,12 +323,12 @@ fn (mut s TcpSocket) connect(a string) ? {
return none return none
} }
_ := error_code() _ := error_code()
write_result := s.@select(.write, connect_timeout) ? write_result := s.@select(.write, net.connect_timeout) ?
if write_result { if write_result {
// succeeded // succeeded
return none return none
} }
except_result := s.@select(.except, connect_timeout) ? except_result := s.@select(.except, net.connect_timeout) ?
if except_result { if except_result {
return err_connect_failed return err_connect_failed
} }

View File

@ -64,7 +64,10 @@ fn test_socket_write_and_read() {
message1 := 'a message 1' message1 := 'a message 1'
socket.write_str(message1) or { assert false } socket.write_str(message1) or { assert false }
mut rbuf := []byte{len: message1.len} mut rbuf := []byte{len: message1.len}
client.read(mut rbuf) client.read(mut rbuf) or {
assert false
return
}
line := rbuf.bytestr() line := rbuf.bytestr()
assert line == message1 assert line == message1
} }
@ -127,8 +130,14 @@ fn test_socket_read_line_long_line_without_eol() {
cleanup(mut server, mut client, mut socket) cleanup(mut server, mut client, mut socket)
} }
message := strings.repeat_string('123', 400) message := strings.repeat_string('123', 400)
socket.write_str(message) socket.write_str(message) or {
socket.write_str('\n') assert false
return
}
socket.write_str('\n') or {
assert false
return
}
line := reader.read_line() or { line := reader.read_line() or {
assert false assert false
return return

View File

@ -33,8 +33,8 @@ pub fn dial_udp(laddr string, raddr string) ?&UdpConn {
} }
return &UdpConn{ return &UdpConn{
sock: sock sock: sock
read_timeout: udp_default_read_timeout read_timeout: net.udp_default_read_timeout
write_timeout: udp_default_write_timeout write_timeout: net.udp_default_write_timeout
} }
} }
@ -162,8 +162,8 @@ pub fn listen_udp(port int) ?&UdpConn {
s := new_udp_socket(port) ? s := new_udp_socket(port) ?
return &UdpConn{ return &UdpConn{
sock: s sock: s
read_timeout: udp_default_read_timeout read_timeout: net.udp_default_read_timeout
write_timeout: udp_default_write_timeout write_timeout: net.udp_default_write_timeout
} }
} }
@ -183,7 +183,7 @@ fn new_udp_socket(local_port int) ?&UdpSocket {
t := true t := true
socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ? socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ?
} $else { } $else {
socket_error(C.fcntl(sockfd, C.F_SETFD, C.O_NONBLOCK)) socket_error(C.fcntl(sockfd, C.F_SETFD, C.O_NONBLOCK)) ?
} }
// In UDP we always have to bind to a port // In UDP we always have to bind to a port
validate_port(local_port) ? validate_port(local_port) ?

View File

@ -53,8 +53,8 @@ fn should_escape(c byte, mode EncodingMode) bool {
// we could possibly allow, and parse will reject them if we // we could possibly allow, and parse will reject them if we
// escape them (because hosts can`t use %-encoding for // escape them (because hosts can`t use %-encoding for
// ASCII bytes). // ASCII bytes).
if c in if
[`!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `:`, `[`, `]`, `<`, `>`, `"`] { c in [`!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `:`, `[`, `]`, `<`, `>`, `"`] {
return false return false
} }
} }
@ -162,7 +162,7 @@ fn unescape(s_ string, mode EncodingMode) ?string {
if s.len > 3 { if s.len > 3 {
s = s[..3] s = s[..3]
} }
return error(error_msg(err_msg_escape, s)) return error(error_msg(urllib.err_msg_escape, s))
} }
// Per https://tools.ietf.org/html/rfc3986#page-21 // Per https://tools.ietf.org/html/rfc3986#page-21
// in the host component %-encoding can only be used // in the host component %-encoding can only be used
@ -171,7 +171,7 @@ fn unescape(s_ string, mode EncodingMode) ?string {
// introduces %25 being allowed to escape a percent sign // introduces %25 being allowed to escape a percent sign
// in IPv6 scoped-address literals. Yay. // in IPv6 scoped-address literals. Yay.
if mode == .encode_host && unhex(s[i + 1]) < 8 && s[i..i + 3] != '%25' { if mode == .encode_host && unhex(s[i + 1]) < 8 && s[i..i + 3] != '%25' {
return error(error_msg(err_msg_escape, s[i..i + 3])) return error(error_msg(urllib.err_msg_escape, s[i..i + 3]))
} }
if mode == .encode_zone { if mode == .encode_zone {
// RFC 6874 says basically 'anything goes' for zone identifiers // RFC 6874 says basically 'anything goes' for zone identifiers
@ -183,7 +183,7 @@ fn unescape(s_ string, mode EncodingMode) ?string {
// But Windows puts spaces here! Yay. // But Windows puts spaces here! Yay.
v := ((unhex(s[i + 1]) << byte(4)) | unhex(s[i + 2])) v := ((unhex(s[i + 1]) << byte(4)) | unhex(s[i + 2]))
if s[i..i + 3] != '%25' && v != ` ` && should_escape(v, .encode_host) { if s[i..i + 3] != '%25' && v != ` ` && should_escape(v, .encode_host) {
error(error_msg(err_msg_escape, s[i..i + 3])) error(error_msg(urllib.err_msg_escape, s[i..i + 3]))
} }
} }
i += 3 i += 3
@ -193,9 +193,8 @@ fn unescape(s_ string, mode EncodingMode) ?string {
i++ i++
} }
else { else {
if (mode == .encode_host || if (mode == .encode_host || mode == .encode_zone) && s[i] < 0x80
mode == .encode_zone) && && should_escape(s[i], mode) {
s[i] < 0x80 && should_escape(s[i], mode) {
error(error_msg('unescape: invalid character in host name', s[i..i + 1])) error(error_msg('unescape: invalid character in host name', s[i..i + 1]))
} }
i++ i++
@ -429,11 +428,12 @@ fn split(s string, sep byte, cutc bool) (string, string) {
pub fn parse(rawurl string) ?URL { pub fn parse(rawurl string) ?URL {
// Cut off #frag // Cut off #frag
u, frag := split(rawurl, `#`, true) u, frag := split(rawurl, `#`, true)
mut url := parse_url(u, false) or { return error(error_msg(err_msg_parse, u)) } mut url := parse_url(u, false) or { return error(error_msg(urllib.err_msg_parse, u)) }
if frag == '' { if frag == '' {
return url return url
} }
f := unescape(frag, .encode_fragment) or { return error(error_msg(err_msg_parse, u)) } f := unescape(frag, .encode_fragment) or { return error(error_msg(urllib.err_msg_parse,
u)) }
url.fragment = f url.fragment = f
return url return url
} }
@ -570,7 +570,7 @@ fn parse_host(host string) ?string {
// parse an IP-Literal in RFC 3986 and RFC 6874. // parse an IP-Literal in RFC 3986 and RFC 6874.
// E.g., '[fe80::1]', '[fe80::1%25en0]', '[fe80::1]:80'. // E.g., '[fe80::1]', '[fe80::1%25en0]', '[fe80::1]:80'.
mut i := host.last_index(']') or { mut i := host.last_index(']') or {
return error(error_msg("parse_host: missing \']\' in host", '')) return error(error_msg("parse_host: missing ']' in host", ''))
} }
mut colon_port := host[i + 1..] mut colon_port := host[i + 1..]
if !valid_optional_port(colon_port) { if !valid_optional_port(colon_port) {
@ -785,7 +785,7 @@ pub fn parse_query(query string) ?Values {
// but any errors will be silent // but any errors will be silent
fn parse_query_silent(query string) Values { fn parse_query_silent(query string) Values {
mut m := new_values() mut m := new_values()
parse_query_values(mut m, query) parse_query_values(mut m, query) or { }
return m return m
} }
@ -1029,7 +1029,8 @@ pub fn valid_userinfo(s string) bool {
continue continue
} }
match r { match r {
`-`, `.`, `_`, `:`, `~`, `!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `%`, `@` { `-`, `.`, `_`, `:`, `~`, `!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `%`,
`@` {
continue continue
} }
else { else {

View File

@ -9,16 +9,16 @@ const (
fn testsuite_begin() { fn testsuite_begin() {
eprintln('testsuite_begin, tfolder = $tfolder') eprintln('testsuite_begin, tfolder = $tfolder')
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
os.mkdir_all(tfolder) os.mkdir_all(tfolder) or { panic(err) }
os.chdir(tfolder) os.chdir(tfolder)
assert os.is_dir(tfolder) assert os.is_dir(tfolder)
} }
fn testsuite_end() { fn testsuite_end() {
os.chdir(os.wd_at_startup) os.chdir(os.wd_at_startup)
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { panic(err) }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
} }
@ -27,7 +27,7 @@ fn test_inode_file_type() {
mut file := os.open_file(filename, 'w', 0o600) or { return } mut file := os.open_file(filename, 'w', 0o600) or { return }
file.close() file.close()
mode := os.inode(filename) mode := os.inode(filename)
os.rm(filename) os.rm(filename) or { panic(err) }
assert mode.typ == .regular assert mode.typ == .regular
} }
@ -36,7 +36,7 @@ fn test_inode_file_owner_permission() {
mut file := os.open_file(filename, 'w', 0o600) or { return } mut file := os.open_file(filename, 'w', 0o600) or { return }
file.close() file.close()
mode := os.inode(filename) mode := os.inode(filename)
os.rm(filename) os.rm(filename) or { }
assert mode.owner.read assert mode.owner.read
assert mode.owner.write assert mode.owner.write
assert !mode.owner.execute assert !mode.owner.execute

View File

@ -46,7 +46,7 @@ pub fn cp_all(src string, dst string, overwrite bool) ? {
} }
if exists(adjusted_path) { if exists(adjusted_path) {
if overwrite { if overwrite {
rm(adjusted_path) rm(adjusted_path) ?
} else { } else {
return error('Destination file path already exist') return error('Destination file path already exist')
} }
@ -65,7 +65,7 @@ pub fn cp_all(src string, dst string, overwrite bool) ? {
mkdir(dp) ? mkdir(dp) ?
} }
cp_all(sp, dp, overwrite) or { cp_all(sp, dp, overwrite) or {
rmdir(dp) rmdir(dp) or { return error(err) }
return error(err) return error(err)
} }
} }
@ -144,7 +144,7 @@ pub fn file_exists(_path string) bool {
[deprecated] [deprecated]
pub fn rmdir_recursive(path string) { pub fn rmdir_recursive(path string) {
eprintln('warning: `os.rmdir_recursive` has been deprecated, use `os.rmdir_all` instead') eprintln('warning: `os.rmdir_recursive` has been deprecated, use `os.rmdir_all` instead')
rmdir_all(path) rmdir_all(path) or { panic(err) }
} }
// rmdir_all recursively removes the specified directory. // rmdir_all recursively removes the specified directory.
@ -154,7 +154,7 @@ pub fn rmdir_all(path string) ? {
for item in items { for item in items {
fullpath := join_path(path, item) fullpath := join_path(path, item)
if is_dir(fullpath) { if is_dir(fullpath) {
rmdir_all(fullpath) rmdir_all(fullpath) or { ret_err = err }
} }
rm(fullpath) or { ret_err = err } rm(fullpath) or { ret_err = err }
} }
@ -315,7 +315,7 @@ pub fn home_dir() string {
// write_file writes `text` data to a file in `path`. // write_file writes `text` data to a file in `path`.
pub fn write_file(path string, text string) ? { pub fn write_file(path string, text string) ? {
mut f := create(path) ? mut f := create(path) ?
f.write(text.bytes()) f.write(text.bytes()) ?
f.close() f.close()
} }

View File

@ -280,7 +280,7 @@ pub fn is_writable_folder(folder string) ?bool {
} }
C.close(x) C.close(x)
} }
rm(tmp_perm_check) rm(tmp_perm_check) ?
return true return true
} }

View File

@ -13,9 +13,9 @@ const args_at_start = os.args.clone()
fn testsuite_begin() { fn testsuite_begin() {
eprintln('testsuite_begin, tfolder = $tfolder') eprintln('testsuite_begin, tfolder = $tfolder')
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
os.mkdir_all(tfolder) os.mkdir_all(tfolder) or { panic(err) }
os.chdir(tfolder) os.chdir(tfolder)
assert os.is_dir(tfolder) assert os.is_dir(tfolder)
// println('args_at_start: $args_at_start') // println('args_at_start: $args_at_start')
@ -25,7 +25,7 @@ fn testsuite_begin() {
fn testsuite_end() { fn testsuite_end() {
os.chdir(os.wd_at_startup) os.chdir(os.wd_at_startup)
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder) assert !os.is_dir(tfolder)
// eprintln('testsuite_end , tfolder = $tfolder removed.') // eprintln('testsuite_end , tfolder = $tfolder removed.')
} }
@ -38,12 +38,12 @@ fn test_open_file() {
os.File{} os.File{}
} }
mut file := os.open_file(filename, 'w+', 0o666) or { panic(err) } mut file := os.open_file(filename, 'w+', 0o666) or { panic(err) }
file.write_str(hello) file.write_str(hello) or { panic(err) }
file.close() file.close()
assert hello.len == os.file_size(filename) assert hello.len == os.file_size(filename)
read_hello := os.read_file(filename) or { panic('error reading file $filename') } read_hello := os.read_file(filename) or { panic('error reading file $filename') }
assert hello == read_hello assert hello == read_hello
os.rm(filename) os.rm(filename) or { panic(err) }
} }
fn test_open_file_binary() { fn test_open_file_binary() {
@ -60,7 +60,7 @@ fn test_open_file_binary() {
assert hello.len == os.file_size(filename) assert hello.len == os.file_size(filename)
read_hello := os.read_bytes(filename) or { panic('error reading file $filename') } read_hello := os.read_bytes(filename) or { panic('error reading file $filename') }
assert bytes == read_hello assert bytes == read_hello
os.rm(filename) os.rm(filename) or { panic(err) }
} }
// fn test_file_get_line() { // fn test_file_get_line() {
@ -87,23 +87,23 @@ fn test_create_file() {
filename := './test1.txt' filename := './test1.txt'
hello := 'hello world!' hello := 'hello world!'
mut f := os.create(filename) or { panic(err) } mut f := os.create(filename) or { panic(err) }
f.write_str(hello) f.write_str(hello) or { panic(err) }
f.close() f.close()
assert hello.len == os.file_size(filename) assert hello.len == os.file_size(filename)
os.rm(filename) os.rm(filename) or { panic(err) }
} }
fn test_is_file() { fn test_is_file() {
// Setup // Setup
work_dir := os.join_path(os.getwd(), 'is_file_test') work_dir := os.join_path(os.getwd(), 'is_file_test')
os.mkdir_all(work_dir) os.mkdir_all(work_dir) or { panic(err) }
tfile := os.join_path(work_dir, 'tmp_file') tfile := os.join_path(work_dir, 'tmp_file')
// Test things that shouldn't be a file // Test things that shouldn't be a file
assert os.is_file(work_dir) == false assert os.is_file(work_dir) == false
assert os.is_file('non-existent_file.tmp') == false assert os.is_file('non-existent_file.tmp') == false
// Test file // Test file
tfile_content := 'temporary file' tfile_content := 'temporary file'
os.write_file(tfile, tfile_content) os.write_file(tfile, tfile_content) or { panic(err) }
assert os.is_file(tfile) assert os.is_file(tfile)
// Test dir symlinks // Test dir symlinks
$if windows { $if windows {
@ -126,11 +126,11 @@ fn test_is_file() {
fn test_write_and_read_string_to_file() { fn test_write_and_read_string_to_file() {
filename := './test1.txt' filename := './test1.txt'
hello := 'hello world!' hello := 'hello world!'
os.write_file(filename, hello) os.write_file(filename, hello) or { panic(err) }
assert hello.len == os.file_size(filename) assert hello.len == os.file_size(filename)
read_hello := os.read_file(filename) or { panic('error reading file $filename') } read_hello := os.read_file(filename) or { panic('error reading file $filename') }
assert hello == read_hello assert hello == read_hello
os.rm(filename) os.rm(filename) or { panic(err) }
} }
// test_write_and_read_bytes checks for regressions made in the functions // test_write_and_read_bytes checks for regressions made in the functions
@ -166,7 +166,7 @@ fn test_write_and_read_bytes() {
assert nread == 0 assert nread == 0
file_read.close() file_read.close()
// We finally delete the test file. // We finally delete the test file.
os.rm(file_name) os.rm(file_name) or { panic(err) }
} }
fn test_create_and_delete_folder() { fn test_create_and_delete_folder() {
@ -175,7 +175,7 @@ fn test_create_and_delete_folder() {
assert os.is_dir(folder) assert os.is_dir(folder)
folder_contents := os.ls(folder) or { panic(err) } folder_contents := os.ls(folder) or { panic(err) }
assert folder_contents.len == 0 assert folder_contents.len == 0
os.rmdir(folder) os.rmdir(folder) or { panic(err) }
folder_exists := os.is_dir(folder) folder_exists := os.is_dir(folder)
assert folder_exists == false assert folder_exists == false
} }
@ -191,61 +191,61 @@ fn test_walk() {
folder := 'test_walk' folder := 'test_walk'
os.mkdir(folder) or { panic(err) } os.mkdir(folder) or { panic(err) }
file1 := folder + os.path_separator + 'test1' file1 := folder + os.path_separator + 'test1'
os.write_file(file1, 'test-1') os.write_file(file1, 'test-1') or { panic(err) }
os.walk(folder, walk_callback) os.walk(folder, walk_callback)
os.rm(file1) os.rm(file1) or { panic(err) }
os.rmdir(folder) os.rmdir(folder) or { panic(err) }
} }
fn test_cp() { fn test_cp() {
old_file_name := 'cp_example.txt' old_file_name := 'cp_example.txt'
new_file_name := 'cp_new_example.txt' new_file_name := 'cp_new_example.txt'
os.write_file(old_file_name, 'Test data 1 2 3, V is awesome #$%^[]!~') os.write_file(old_file_name, 'Test data 1 2 3, V is awesome #$%^[]!~') or { panic(err) }
os.cp(old_file_name, new_file_name) or { panic('$err: errcode: $errcode') } os.cp(old_file_name, new_file_name) or { panic('$err: errcode: $errcode') }
old_file := os.read_file(old_file_name) or { panic(err) } old_file := os.read_file(old_file_name) or { panic(err) }
new_file := os.read_file(new_file_name) or { panic(err) } new_file := os.read_file(new_file_name) or { panic(err) }
assert old_file == new_file assert old_file == new_file
os.rm(old_file_name) os.rm(old_file_name) or { panic(err) }
os.rm(new_file_name) os.rm(new_file_name) or { panic(err) }
} }
fn test_mv() { fn test_mv() {
work_dir := os.join_path(os.getwd(), 'mv_test') work_dir := os.join_path(os.getwd(), 'mv_test')
os.mkdir_all(work_dir) os.mkdir_all(work_dir) or { panic(err) }
// Setup test files // Setup test files
tfile1 := os.join_path(work_dir, 'file') tfile1 := os.join_path(work_dir, 'file')
tfile2 := os.join_path(work_dir, 'file.test') tfile2 := os.join_path(work_dir, 'file.test')
tfile3 := os.join_path(work_dir, 'file.3') tfile3 := os.join_path(work_dir, 'file.3')
tfile_content := 'temporary file' tfile_content := 'temporary file'
os.write_file(tfile1, tfile_content) os.write_file(tfile1, tfile_content) or { panic(err) }
os.write_file(tfile2, tfile_content) os.write_file(tfile2, tfile_content) or { panic(err) }
// Setup test dirs // Setup test dirs
tdir1 := os.join_path(work_dir, 'dir') tdir1 := os.join_path(work_dir, 'dir')
tdir2 := os.join_path(work_dir, 'dir2') tdir2 := os.join_path(work_dir, 'dir2')
tdir3 := os.join_path(work_dir, 'dir3') tdir3 := os.join_path(work_dir, 'dir3')
mkdir(tdir1) os.mkdir(tdir1) or { panic(err) }
mkdir(tdir2) os.mkdir(tdir2) or { panic(err) }
// Move file with no extension to dir // Move file with no extension to dir
os.mv(tfile1, tdir1) os.mv(tfile1, tdir1) or { panic(err) }
mut expected := os.join_path(tdir1, 'file') mut expected := os.join_path(tdir1, 'file')
assert os.exists(expected) && !is_dir(expected) == true assert os.exists(expected) && !is_dir(expected) == true
// Move dir with contents to other dir // Move dir with contents to other dir
os.mv(tdir1, tdir2) os.mv(tdir1, tdir2) or { panic(err) }
expected = os.join_path(tdir2, 'dir') expected = os.join_path(tdir2, 'dir')
assert os.exists(expected) && is_dir(expected) == true assert os.exists(expected) && is_dir(expected) == true
expected = os.join_path(tdir2, 'dir', 'file') expected = os.join_path(tdir2, 'dir', 'file')
assert os.exists(expected) && !is_dir(expected) == true assert os.exists(expected) && !is_dir(expected) == true
// Move dir with contents to other dir (by renaming) // Move dir with contents to other dir (by renaming)
os.mv(os.join_path(tdir2, 'dir'), tdir3) os.mv(os.join_path(tdir2, 'dir'), tdir3) or { panic(err) }
expected = tdir3 expected = tdir3
assert os.exists(expected) && is_dir(expected) == true assert os.exists(expected) && is_dir(expected) == true
assert os.is_dir_empty(tdir2) == true assert os.is_dir_empty(tdir2) == true
// Move file with extension to dir // Move file with extension to dir
os.mv(tfile2, tdir2) os.mv(tfile2, tdir2) or { panic(err) }
expected = os.join_path(tdir2, 'file.test') expected = os.join_path(tdir2, 'file.test')
assert os.exists(expected) && !is_dir(expected) == true assert os.exists(expected) && !is_dir(expected) == true
// Move file to dir (by renaming) // Move file to dir (by renaming)
os.mv(os.join_path(tdir2, 'file.test'), tfile3) os.mv(os.join_path(tdir2, 'file.test'), tfile3) or { panic(err) }
expected = tfile3 expected = tfile3
assert os.exists(expected) && !is_dir(expected) == true assert os.exists(expected) && !is_dir(expected) == true
} }
@ -253,14 +253,14 @@ fn test_mv() {
fn test_cp_r() { fn test_cp_r() {
// fileX -> dir/fileX // fileX -> dir/fileX
// NB: clean up of the files happens inside the cleanup_leftovers function // NB: clean up of the files happens inside the cleanup_leftovers function
os.write_file('ex1.txt', 'wow!') os.write_file('ex1.txt', 'wow!') or { panic(err) }
os.mkdir('ex') or { panic(err) } os.mkdir('ex') or { panic(err) }
os.cp_all('ex1.txt', 'ex', false) or { panic(err) } os.cp_all('ex1.txt', 'ex', false) or { panic(err) }
old := os.read_file('ex1.txt') or { panic(err) } old := os.read_file('ex1.txt') or { panic(err) }
new := os.read_file('ex/ex1.txt') or { panic(err) } new := os.read_file('ex/ex1.txt') or { panic(err) }
assert old == new assert old == new
os.mkdir('ex/ex2') or { panic(err) } os.mkdir('ex/ex2') or { panic(err) }
os.write_file('ex2.txt', 'great!') os.write_file('ex2.txt', 'great!') or { panic(err) }
os.cp_all('ex2.txt', 'ex/ex2', false) or { panic(err) } os.cp_all('ex2.txt', 'ex/ex2', false) or { panic(err) }
old2 := os.read_file('ex2.txt') or { panic(err) } old2 := os.read_file('ex2.txt') or { panic(err) }
new2 := os.read_file('ex/ex2/ex2.txt') or { panic(err) } new2 := os.read_file('ex/ex2/ex2.txt') or { panic(err) }
@ -274,12 +274,12 @@ fn test_tmpdir() {
assert t.len > 0 assert t.len > 0
assert os.is_dir(t) assert os.is_dir(t)
tfile := t + os.path_separator + 'tmpfile.txt' tfile := t + os.path_separator + 'tmpfile.txt'
os.rm(tfile) // just in case os.rm(tfile) or { } // just in case
tfile_content := 'this is a temporary file' tfile_content := 'this is a temporary file'
os.write_file(tfile, tfile_content) os.write_file(tfile, tfile_content) or { panic(err) }
tfile_content_read := os.read_file(tfile) or { panic(err) } tfile_content_read := os.read_file(tfile) or { panic(err) }
assert tfile_content_read == tfile_content assert tfile_content_read == tfile_content
os.rm(tfile) os.rm(tfile) or { panic(err) }
} }
fn test_is_writable_folder() { fn test_is_writable_folder() {
@ -299,15 +299,15 @@ fn test_make_symlink_check_is_link_and_remove_symlink() {
} }
folder := 'tfolder' folder := 'tfolder'
symlink := 'tsymlink' symlink := 'tsymlink'
os.rm(symlink) os.rm(symlink) or { }
os.rm(folder) os.rm(folder) or { }
os.mkdir(folder) or { panic(err) } os.mkdir(folder) or { panic(err) }
folder_contents := os.ls(folder) or { panic(err) } folder_contents := os.ls(folder) or { panic(err) }
assert folder_contents.len == 0 assert folder_contents.len == 0
os.system('ln -s $folder $symlink') os.system('ln -s $folder $symlink')
assert os.is_link(symlink) == true assert os.is_link(symlink) == true
os.rm(symlink) os.rm(symlink) or { panic(err) }
os.rm(folder) os.rm(folder) or { panic(err) }
folder_exists := os.is_dir(folder) folder_exists := os.is_dir(folder)
assert folder_exists == false assert folder_exists == false
symlink_exists := os.is_link(symlink) symlink_exists := os.is_link(symlink)
@ -343,8 +343,8 @@ fn test_symlink() {
os.symlink('symlink', 'symlink2') or { panic(err) } os.symlink('symlink', 'symlink2') or { panic(err) }
assert os.exists('symlink2') assert os.exists('symlink2')
// cleanup // cleanup
os.rm('symlink') os.rm('symlink') or { panic(err) }
os.rm('symlink2') os.rm('symlink2') or { panic(err) }
} }
fn test_is_executable_writable_readable() { fn test_is_executable_writable_readable() {
@ -367,7 +367,7 @@ fn test_is_executable_writable_readable() {
assert os.is_executable(file_name) assert os.is_executable(file_name)
} }
// We finally delete the test file. // We finally delete the test file.
os.rm(file_name) os.rm(file_name) or { panic(err) }
} }
fn test_ext() { fn test_ext() {
@ -438,7 +438,7 @@ fn test_write_file_array_bytes() {
for i in 0 .. maxn { for i in 0 .. maxn {
arr[i] = 65 + byte(i) arr[i] = 65 + byte(i)
} }
os.write_file_array(fpath, arr) os.write_file_array(fpath, arr) or { panic(err) }
rarr := os.read_bytes(fpath) or { panic(err) } rarr := os.read_bytes(fpath) or { panic(err) }
assert arr == rarr assert arr == rarr
// eprintln(arr.str()) // eprintln(arr.str())
@ -451,7 +451,7 @@ fn test_write_file_array_structs() {
for i in 0 .. maxn { for i in 0 .. maxn {
arr[i] = IntPoint{65 + i, 65 + i + 10} arr[i] = IntPoint{65 + i, 65 + i + 10}
} }
os.write_file_array(fpath, arr) os.write_file_array(fpath, arr) or { panic(err) }
rarr := os.read_file_array<IntPoint>(fpath) rarr := os.read_file_array<IntPoint>(fpath)
assert rarr == arr assert rarr == arr
assert rarr.len == maxn assert rarr.len == maxn
@ -519,6 +519,6 @@ fn test_posix_set_bit() {
} }
mode = u32(s.st_mode) & 0o7777 mode = u32(s.st_mode) & 0o7777
assert mode == 0o0755 assert mode == 0o0755
rm(fpath) rm(fpath) or { }
} }
} }

View File

@ -9,9 +9,10 @@ import time
#include <termios.h> #include <termios.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <signal.h> #include <signal.h>
fn C.tcgetattr() fn C.tcgetattr()
fn C.tcsetattr() fn C.tcsetattr()
fn C.ioctl(fd int, request u64, arg voidptr) int fn C.ioctl(fd int, request u64, arg voidptr) int
struct C.termios { struct C.termios {
@ -103,7 +104,6 @@ fn (mut ctx Context) termios_setup() ? {
// feature-test rgb (truecolor) support // feature-test rgb (truecolor) support
ctx.enable_rgb = supports_truecolor() ctx.enable_rgb = supports_truecolor()
} }
// Prevent stdin from blocking by making its read time 0 // Prevent stdin from blocking by making its read time 0
termios.c_cc[C.VTIME] = 0 termios.c_cc[C.VTIME] = 0
termios.c_cc[C.VMIN] = 0 termios.c_cc[C.VMIN] = 0
@ -124,7 +124,7 @@ fn (mut ctx Context) termios_setup() ? {
os.signal(C.SIGCONT, fn () { os.signal(C.SIGCONT, fn () {
mut c := ctx_ptr mut c := ctx_ptr
if c != 0 { if c != 0 {
c.termios_setup() c.termios_setup() or { panic(err) }
c.window_height, c.window_width = get_terminal_size() c.window_height, c.window_width = get_terminal_size()
mut event := &Event{ mut event := &Event{
typ: .resized typ: .resized
@ -166,10 +166,14 @@ fn get_cursor_position() (int, int) {
print('\033[6n') print('\033[6n')
buf := malloc(25) buf := malloc(25)
len := C.read(C.STDIN_FILENO, buf, 24) len := C.read(C.STDIN_FILENO, buf, 24)
unsafe { buf[len] = 0 } unsafe {
buf[len] = 0
}
s := tos(buf, len) s := tos(buf, len)
a := s[2..].split(';') a := s[2..].split(';')
if a.len != 2 { return -1, -1 } if a.len != 2 {
return -1, -1
}
return a[0].int(), a[1].int() return a[0].int(), a[1].int()
} }
@ -184,14 +188,16 @@ fn supports_truecolor() bool {
print('\x1bP\$qm\x1b\\') print('\x1bP\$qm\x1b\\')
buf := malloc(25) buf := malloc(25)
len := C.read(C.STDIN_FILENO, buf, 24) len := C.read(C.STDIN_FILENO, buf, 24)
unsafe { buf[len] = 0 } unsafe {
buf[len] = 0
}
s := tos(buf, len) s := tos(buf, len)
return '1:2:3' in s return '1:2:3' in s
} }
fn termios_reset() { fn termios_reset() {
C.tcsetattr(C.STDIN_FILENO, C.TCSAFLUSH /* C.TCSANOW ?? */, &termios_at_startup) // C.TCSANOW ??
C.tcsetattr(C.STDIN_FILENO, C.TCSAFLUSH, &ui.termios_at_startup)
print('\x1b[?1003l\x1b[?1006l\x1b[?25h') print('\x1b[?1003l\x1b[?1006l\x1b[?25h')
c := ctx_ptr c := ctx_ptr
if c != 0 && c.cfg.use_alternate_buffer { if c != 0 && c.cfg.use_alternate_buffer {
@ -201,7 +207,6 @@ fn termios_reset() {
} }
/////////////////////////////////////////// ///////////////////////////////////////////
// TODO: do multiple sleep/read cycles, rather than one big one // TODO: do multiple sleep/read cycles, rather than one big one
fn (mut ctx Context) termios_loop() { fn (mut ctx Context) termios_loop() {
frame_time := 1_000_000 / ctx.cfg.frame_rate frame_time := 1_000_000 / ctx.cfg.frame_rate
@ -221,7 +226,8 @@ fn (mut ctx Context) termios_loop() {
sw.restart() sw.restart()
if ctx.cfg.event_fn != voidptr(0) { if ctx.cfg.event_fn != voidptr(0) {
unsafe { unsafe {
len := C.read(C.STDIN_FILENO, byteptr(ctx.read_buf.data) + ctx.read_buf.len, ctx.read_buf.cap - ctx.read_buf.len) len := C.read(C.STDIN_FILENO, byteptr(ctx.read_buf.data) + ctx.read_buf.len,
ctx.read_buf.cap - ctx.read_buf.len)
ctx.resize_arr(ctx.read_buf.len + len) ctx.resize_arr(ctx.read_buf.len + len)
} }
if ctx.read_buf.len > 0 { if ctx.read_buf.len > 0 {
@ -243,7 +249,9 @@ fn (mut ctx Context) parse_events() {
mut nr_iters := 0 mut nr_iters := 0
for ctx.read_buf.len > 0 { for ctx.read_buf.len > 0 {
nr_iters++ nr_iters++
if nr_iters > 100 { ctx.shift(1) } if nr_iters > 100 {
ctx.shift(1)
}
mut event := &Event(0) mut event := &Event(0)
if ctx.read_buf[0] == 0x1b { if ctx.read_buf[0] == 0x1b {
e, len := escape_sequence(ctx.read_buf.bytestr()) e, len := escape_sequence(ctx.read_buf.bytestr())
@ -272,30 +280,39 @@ fn single_char(buf string) &Event {
match ch { match ch {
// special handling for `ctrl + letter` // special handling for `ctrl + letter`
// TODO: Fix assoc in V and remove this workaround :/ // TODO: Fix assoc in V and remove this workaround :/
// 1 ... 26 { event = Event{ ...event, code: KeyCode(96 | ch), modifiers: ctrl } } // 1 ... 26 { event = Event{ ...event, code: KeyCode(96 | ch), modifiers: ctrl } }
// 65 ... 90 { event = Event{ ...event, code: KeyCode(32 | ch), modifiers: shift } } // 65 ... 90 { event = Event{ ...event, code: KeyCode(32 | ch), modifiers: shift } }
// The bit `or`s here are really just `+`'s, just written in this way for a tiny performance improvement // The bit `or`s here are really just `+`'s, just written in this way for a tiny performance improvement
// don't treat tab, enter as ctrl+i, ctrl+j // don't treat tab, enter as ctrl+i, ctrl+j
1 ... 8, 11 ... 26 { event = &Event{ typ: event.typ, ascii: event.ascii, utf8: event.utf8, code: KeyCode(96 | ch), modifiers: ctrl } } 1...8, 11...26 { event = &Event{
65 ... 90 { event = &Event{ typ: event.typ, ascii: event.ascii, utf8: event.utf8, code: KeyCode(32 | ch), modifiers: shift } } typ: event.typ
ascii: event.ascii
utf8: event.utf8
code: KeyCode(96 | ch)
modifiers: ctrl
} }
65...90 { event = &Event{
typ: event.typ
ascii: event.ascii
utf8: event.utf8
code: KeyCode(32 | ch)
modifiers: shift
} }
else {} else {}
} }
return event return event
} }
[inline]
// Gets an entire, independent escape sequence from the buffer // Gets an entire, independent escape sequence from the buffer
// Normally, this just means reading until the first letter, but there are some exceptions... // Normally, this just means reading until the first letter, but there are some exceptions...
fn escape_end(buf string) int { fn escape_end(buf string) int {
mut i := 0 mut i := 0
for { for {
if i + 1 == buf.len { return buf.len } if i + 1 == buf.len {
return buf.len
}
if buf[i].is_letter() || buf[i] == `~` { if buf[i].is_letter() || buf[i] == `~` {
if buf[i] == `O` && i + 2 <= buf.len { if buf[i] == `O` && i + 2 <= buf.len {
@ -306,7 +323,9 @@ fn escape_end(buf string) int {
} }
return i + 1 return i + 1
// escape hatch to avoid potential issues/crashes, although ideally this should never eval to true // escape hatch to avoid potential issues/crashes, although ideally this should never eval to true
} else if buf[i + 1] == 0x1b { return i + 1 } } else if buf[i + 1] == 0x1b {
return i + 1
}
i++ i++
} }
// this point should be unreachable // this point should be unreachable
@ -339,32 +358,49 @@ fn escape_sequence(buf_ string) (&Event, int) {
modifiers: c.modifiers | alt modifiers: c.modifiers | alt
}, 2 }, 2
} }
// ---------------- // ----------------
// Mouse events // Mouse events
// ---------------- // ----------------
// Documentation: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking // Documentation: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
if buf.len > 2 && buf[1] == `<` { if buf.len > 2 && buf[1] == `<` {
split := buf[2..].split(';') split := buf[2..].split(';')
if split.len < 3 { return &Event(0), 0 } if split.len < 3 {
return &Event(0), 0
}
typ, x, y := split[0].int(), split[1].int(), split[2].int() typ, x, y := split[0].int(), split[1].int(), split[2].int()
lo := typ & 0b00011 lo := typ & 0b00011
hi := typ & 0b11100 hi := typ & 0b11100
mut modifiers := u32(0) mut modifiers := u32(0)
if hi & 4 != 0 { modifiers |= shift } if hi & 4 != 0 {
if hi & 8 != 0 { modifiers |= alt } modifiers |= shift
if hi & 16 != 0 { modifiers |= ctrl } }
if hi & 8 != 0 {
modifiers |= alt
}
if hi & 16 != 0 {
modifiers |= ctrl
}
match typ { match typ {
0...31 { 0...31 {
last := buf[buf.len - 1] last := buf[buf.len - 1]
button := if lo < 3 { MouseButton(lo + 1) } else { MouseButton.unknown } button := if lo < 3 { MouseButton(lo + 1) } else { MouseButton.unknown }
event := if last == `m` || lo == 3 { EventType.mouse_up } else { EventType.mouse_down } event := if last == `m` || lo == 3 {
EventType.mouse_up
} else {
EventType.mouse_down
}
return &Event{ typ: event, x: x, y: y, button: button, modifiers: modifiers utf8: single }, end return &Event{
typ: event
x: x
y: y
button: button
modifiers: modifiers
utf8: single
}, end
} }
32...63 { 32...63 {
button, event := if lo < 3 { button, event := if lo < 3 {
@ -373,17 +409,34 @@ fn escape_sequence(buf_ string) (&Event, int) {
MouseButton.unknown, EventType.mouse_move MouseButton.unknown, EventType.mouse_move
} }
return &Event{ typ: event, x: x, y: y, button: button, modifiers: modifiers, utf8: single }, end return &Event{
typ: event
x: x
y: y
button: button
modifiers: modifiers
utf8: single
}, end
} }
64...95 { 64...95 {
direction := if typ & 1 == 0 { Direction.down } else { Direction.up } direction := if typ & 1 == 0 { Direction.down } else { Direction.up }
return &Event{ typ: .mouse_scroll, x: x, y: y, direction: direction, modifiers: modifiers, utf8: single }, end return &Event{
} else { typ: .mouse_scroll
return &Event{ typ: .unknown, utf8: single }, end x: x
y: y
direction: direction
modifiers: modifiers
utf8: single
}, end
}
else {
return &Event{
typ: .unknown
utf8: single
}, end
} }
} }
} }
// ---------------------------- // ----------------------------
// Special key combinations // Special key combinations
// ---------------------------- // ----------------------------
@ -455,5 +508,10 @@ fn escape_sequence(buf_ string) (&Event, int) {
} }
} }
return &Event{ typ: .key_down, code: code, utf8: single, modifiers: modifiers }, end return &Event{
typ: .key_down
code: code
utf8: single
modifiers: modifiers
}, end
} }

View File

@ -35,7 +35,7 @@ pub fn (mut b Builder) build_c(v_files []string, out_file string) {
b.info('build_c($out_file)') b.info('build_c($out_file)')
output2 := b.gen_c(v_files) output2 := b.gen_c(v_files)
mut f := os.create(out_file) or { panic(err) } mut f := os.create(out_file) or { panic(err) }
f.writeln(output2) f.writeln(output2) or { panic(err) }
f.close() f.close()
// os.write_file(out_file, b.gen_c(v_files)) // os.write_file(out_file, b.gen_c(v_files))
} }
@ -75,9 +75,9 @@ pub fn (mut b Builder) compile_c() {
bundle_name := b.pref.out_name.split('/').last() bundle_name := b.pref.out_name.split('/').last()
bundle_id := if b.pref.bundle_id != '' { b.pref.bundle_id } else { 'app.vlang.$bundle_name' } bundle_id := if b.pref.bundle_id != '' { b.pref.bundle_id } else { 'app.vlang.$bundle_name' }
display_name := if b.pref.display_name != '' { b.pref.display_name } else { bundle_name } display_name := if b.pref.display_name != '' { b.pref.display_name } else { bundle_name }
os.mkdir('${display_name}.app') os.mkdir('${display_name}.app') or { panic(err) }
os.write_file('${display_name}.app/Info.plist', make_ios_plist(display_name, bundle_id, os.write_file('${display_name}.app/Info.plist', make_ios_plist(display_name, bundle_id,
bundle_name, 1)) bundle_name, 1)) or { panic(err) }
} }
b.cc() b.cc()
} }

View File

@ -92,7 +92,7 @@ fn (mut v Builder) post_process_c_compiler_output(res os.Result) {
if v.pref.is_verbose { if v.pref.is_verbose {
eprintln('>> remove tmp file: $tmpfile') eprintln('>> remove tmp file: $tmpfile')
} }
os.rm(tmpfile) os.rm(tmpfile) or { panic(err) }
} }
} }
return return
@ -414,7 +414,9 @@ fn (mut v Builder) setup_output_name() {
if v.pref.is_verbose { if v.pref.is_verbose {
println('Building $v.pref.path to $v.pref.out_name ...') println('Building $v.pref.path to $v.pref.out_name ...')
} }
v.pref.cache_manager.save('.description.txt', v.pref.path, '${v.pref.path:-30} @ $v.pref.cache_manager.vopts\n') v.pref.cache_manager.save('.description.txt', v.pref.path, '${v.pref.path:-30} @ $v.pref.cache_manager.vopts\n') or {
panic(err)
}
// println('v.table.imports:') // println('v.table.imports:')
// println(v.table.imports) // println(v.table.imports)
} }
@ -734,7 +736,7 @@ fn (mut b Builder) cc_linux_cross() {
b.setup_output_name() b.setup_output_name()
parent_dir := os.vmodules_dir() parent_dir := os.vmodules_dir()
if !os.exists(parent_dir) { if !os.exists(parent_dir) {
os.mkdir(parent_dir) os.mkdir(parent_dir) or { panic(err) }
} }
sysroot := os.join_path(os.vmodules_dir(), 'linuxroot') sysroot := os.join_path(os.vmodules_dir(), 'linuxroot')
if !os.is_dir(sysroot) { if !os.is_dir(sysroot) {
@ -917,7 +919,7 @@ fn (mut v Builder) build_thirdparty_obj_file(path string, moduleflags []cflag.CF
// for example thirdparty\tcc\lib\openlibm.o // for example thirdparty\tcc\lib\openlibm.o
// the best we can do for them is just copy them, // the best we can do for them is just copy them,
// and hope that they work with any compiler... // and hope that they work with any compiler...
os.cp(obj_path, opath) os.cp(obj_path, opath) or { panic(err) }
return return
} }
println('$obj_path not found, building it in $opath ...') println('$obj_path not found, building it in $opath ...')
@ -943,7 +945,9 @@ fn (mut v Builder) build_thirdparty_obj_file(path string, moduleflags []cflag.CF
verror(res.output) verror(res.output)
return return
} }
v.pref.cache_manager.save('.description.txt', obj_path, '${obj_path:-30} @ $cmd\n') v.pref.cache_manager.save('.description.txt', obj_path, '${obj_path:-30} @ $cmd\n') or {
panic(err)
}
println(res.output) println(res.output)
} }

View File

@ -93,12 +93,12 @@ fn (mut b Builder) run_compiled_executable_and_exit() {
} }
if b.pref.os == .ios { if b.pref.os == .ios {
device := '"iPhone SE (2nd generation)"' device := '"iPhone SE (2nd generation)"'
os.exec('xcrun simctl boot $device') os.exec('xcrun simctl boot $device') or { panic(err) }
bundle_name := b.pref.out_name.split('/').last() bundle_name := b.pref.out_name.split('/').last()
display_name := if b.pref.display_name != '' { b.pref.display_name } else { bundle_name } display_name := if b.pref.display_name != '' { b.pref.display_name } else { bundle_name }
os.exec('xcrun simctl install $device ${display_name}.app') os.exec('xcrun simctl install $device ${display_name}.app') or { panic(err) }
bundle_id := if b.pref.bundle_id != '' { b.pref.bundle_id } else { 'app.vlang.$bundle_name' } bundle_id := if b.pref.bundle_id != '' { b.pref.bundle_id } else { 'app.vlang.$bundle_name' }
os.exec('xcrun simctl launch $device $bundle_id') os.exec('xcrun simctl launch $device $bundle_id') or { panic(err) }
} else { } else {
exefile := os.real_path(b.pref.out_name) exefile := os.real_path(b.pref.out_name)
mut cmd := '"$exefile"' mut cmd := '"$exefile"'
@ -133,7 +133,7 @@ fn (mut v Builder) cleanup_run_executable_after_exit(exefile string) {
} }
if os.is_file(exefile) { if os.is_file(exefile) {
v.pref.vrun_elog('remove run executable: $exefile') v.pref.vrun_elog('remove run executable: $exefile')
os.rm(exefile) os.rm(exefile) or { panic(err) }
} }
} }

View File

@ -29,7 +29,7 @@ pub fn (mut b Builder) build_js(v_files []string, out_file string) {
b.info('build_js($out_file)') b.info('build_js($out_file)')
output := b.gen_js(v_files) output := b.gen_js(v_files)
mut f := os.create(out_file) or { panic(err) } mut f := os.create(out_file) or { panic(err) }
f.writeln(output) f.writeln(output) or { panic(err) }
f.close() f.close()
} }

View File

@ -315,7 +315,7 @@ pub fn (mut v Builder) cc_msvc() {
// println(res) // println(res)
// println('C OUTPUT:') // println('C OUTPUT:')
// Always remove the object file - it is completely unnecessary // Always remove the object file - it is completely unnecessary
os.rm(out_name_obj) os.rm(out_name_obj) or { panic(err) }
} }
fn (mut v Builder) build_thirdparty_obj_file_with_msvc(path string, moduleflags []cflag.CFlag) { fn (mut v Builder) build_thirdparty_obj_file_with_msvc(path string, moduleflags []cflag.CFlag) {

View File

@ -1930,10 +1930,8 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
if expr is ast.CallExpr { if expr is ast.CallExpr {
if expr.return_type.has_flag(.optional) { if expr.return_type.has_flag(.optional) {
if expr.or_block.kind == .absent { if expr.or_block.kind == .absent {
if ret_type != table.void_type { c.error('${expr.name}() returns an option, so it should have either an `or {}` block, or `?` at the end',
c.error('${expr.name}() returns an option but is missing an `or {}` block',
expr.pos) expr.pos)
}
} else { } else {
c.check_or_expr(expr.or_block, ret_type, expr.return_type.clear_flag(.optional)) c.check_or_expr(expr.or_block, ret_type, expr.return_type.clear_flag(.optional))
} }

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/optional_method_err.vv:17:10: error: inc_to_limit() returns an option but is missing an `or {}` block vlib/v/checker/tests/optional_method_err.vv:17:10: error: inc_to_limit() returns an option, so it should have either an `or {}` block, or `?` at the end
15 | mut a := Abc{} 15 | mut a := Abc{}
16 | for _ in 0 .. 4 { 16 | for _ in 0 .. 4 {
17 | _ := a.inc_to_limit(2) 17 | _ := a.inc_to_limit(2)

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/optional_void_called_as_normal.vv:7:2: error: foo() returns an option, so it should have either an `or {}` block, or `?` at the end
5 | fn main() {
6 | // Calling foo() without ? or an or block, should be an error.
7 | foo()
| ~~~~~
8 | }

View File

@ -0,0 +1,8 @@
fn foo() ? {
println('foo is called')
}
fn main() {
// Calling foo() without ? or an or block, should be an error.
foo()
}

View File

@ -179,7 +179,7 @@ fn (mut task TaskDescription) execute() {
res := os.exec(cli_cmd) or { panic(err) } res := os.exec(cli_cmd) or { panic(err) }
expected_out_path := program.replace('.vv', '') + task.result_extension expected_out_path := program.replace('.vv', '') + task.result_extension
if should_autofix && !os.exists(expected_out_path) { if should_autofix && !os.exists(expected_out_path) {
os.write_file(expected_out_path, '') os.write_file(expected_out_path, '') or { panic(err) }
} }
mut expected := os.read_file(expected_out_path) or { panic(err) } mut expected := os.read_file(expected_out_path) or { panic(err) }
task.expected = clean_line_endings(expected) task.expected = clean_line_endings(expected)
@ -192,7 +192,7 @@ fn (mut task TaskDescription) execute() {
if task.expected != task.found___ { if task.expected != task.found___ {
task.is_error = true task.is_error = true
if should_autofix { if should_autofix {
os.write_file(expected_out_path, res.output) os.write_file(expected_out_path, res.output) or { panic(err) }
} }
} }
} }

View File

@ -67,7 +67,7 @@ fn test_fmt() {
continue continue
} }
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename') vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename')
os.write_file(vfmt_result_file, result_ocontent) os.write_file(vfmt_result_file, result_ocontent) or { panic(err) }
eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file)) eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file))
continue continue
} }

View File

@ -58,7 +58,7 @@ fn test_fmt() {
continue continue
} }
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename') vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename')
os.write_file(vfmt_result_file, result_ocontent) os.write_file(vfmt_result_file, result_ocontent) or { panic(err) }
eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file)) eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file))
continue continue
} }

View File

@ -56,7 +56,7 @@ fn test_vlib_fmt() {
continue continue
} }
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename') vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename')
os.write_file(vfmt_result_file, result_ocontent) os.write_file(vfmt_result_file, result_ocontent) or { panic(err) }
eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file)) eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file))
continue continue
} }

View File

@ -7,7 +7,7 @@ const (
) )
fn testsuite_end() { fn testsuite_end() {
os.rmdir_all(main.output_dir) os.rmdir_all(output_dir) or { }
} }
const there_is_node_available = is_nodejs_working() const there_is_node_available = is_nodejs_working()
@ -15,22 +15,22 @@ const there_is_node_available = is_nodejs_working()
fn test_example_compilation() { fn test_example_compilation() {
vexe := os.getenv('VEXE') vexe := os.getenv('VEXE')
os.chdir(os.dir(vexe)) os.chdir(os.dir(vexe))
os.mkdir_all(main.output_dir) os.mkdir_all(output_dir) or { panic(err) }
files := find_test_files() files := find_test_files()
for file in files { for file in files {
path := os.join_path(main.test_dir, file) path := os.join_path(test_dir, file)
println('Testing $file') println('Testing $file')
v_code := os.system('$vexe $main.v_options -o $main.output_dir${file}.js $path') v_code := os.system('$vexe $v_options -o $output_dir${file}.js $path')
if v_code != 0 { if v_code != 0 {
assert false assert false
} }
// Compilation failed // Compilation failed
assert v_code == 0 assert v_code == 0
if !main.there_is_node_available { if !there_is_node_available {
println(' ... skipping running $file, there is no NodeJS present') println(' ... skipping running $file, there is no NodeJS present')
continue continue
} }
js_code := os.system('node $main.output_dir${file}.js') js_code := os.system('node $output_dir${file}.js')
if js_code != 0 { if js_code != 0 {
assert false assert false
} }
@ -40,7 +40,7 @@ fn test_example_compilation() {
} }
fn find_test_files() []string { fn find_test_files() []string {
files := os.ls(main.test_dir) or { panic(err) } files := os.ls(test_dir) or { panic(err) }
// The life example never exits, so tests would hang with it, skip // The life example never exits, so tests would hang with it, skip
mut tests := files.filter(it.ends_with('.v')).filter(it != 'life.v') mut tests := files.filter(it.ends_with('.v')).filter(it != 'life.v')
tests.sort() tests.sort()

View File

@ -15,12 +15,10 @@ fn test_x64() {
vexe := os.getenv('VEXE') vexe := os.getenv('VEXE')
vroot := os.dir(vexe) vroot := os.dir(vexe)
dir := os.join_path(vroot, 'vlib/v/gen/x64/tests') dir := os.join_path(vroot, 'vlib/v/gen/x64/tests')
files := os.ls(dir) or { files := os.ls(dir) or { panic(err) }
panic(err)
}
// //
wrkdir := os.join_path(os.temp_dir(), 'vtests', 'x64') wrkdir := os.join_path(os.temp_dir(), 'vtests', 'x64')
os.mkdir_all(wrkdir) os.mkdir_all(wrkdir) or { panic(err) }
os.chdir(wrkdir) os.chdir(wrkdir)
tests := files.filter(it.ends_with('.vv')) tests := files.filter(it.ends_with('.vv'))
if tests.len == 0 { if tests.len == 0 {
@ -48,9 +46,7 @@ fn test_x64() {
eprintln(res.output) eprintln(res.output)
continue continue
} }
mut expected := os.read_file('$dir/${test}.out') or { mut expected := os.read_file('$dir/${test}.out') or { panic(err) }
panic(err)
}
expected = expected.trim_right('\r\n').replace('\r\n', '\n') expected = expected.trim_right('\r\n').replace('\r\n', '\n')
mut found := res.output.trim_right('\r\n').replace('\r\n', '\n') mut found := res.output.trim_right('\r\n').replace('\r\n', '\n')
found = found.trim_space() found = found.trim_space()

View File

@ -127,7 +127,7 @@ fn protected_load_lib(mut r live.LiveReloadInfo, new_lib_path string) {
elog(r, '> load_lib OK, new live_lib: $r.live_lib') elog(r, '> load_lib OK, new live_lib: $r.live_lib')
// removing the .so file from the filesystem after dlopen-ing // removing the .so file from the filesystem after dlopen-ing
// it is safe, since it will still be mapped in memory // it is safe, since it will still be mapped in memory
os.rm(new_lib_path) os.rm(new_lib_path) or { }
} }
// NB: r.reloader() is executed in a new, independent thread // NB: r.reloader() is executed in a new, independent thread

View File

@ -60,8 +60,8 @@ fn atomic_write_source(source string) {
// NB: here wrtiting is done in 2 steps, since os.write_file can take some time, // NB: here wrtiting is done in 2 steps, since os.write_file can take some time,
// during which the file will be modified, but it will still be not completely written. // during which the file will be modified, but it will still be not completely written.
// The os.mv after that, guarantees that the reloader will see a complete valid V program. // The os.mv after that, guarantees that the reloader will see a complete valid V program.
os.write_file(tmp_file, source) os.write_file(tmp_file, source) or { panic(err) }
os.mv(tmp_file, source_file) os.mv(tmp_file, source_file) or { panic(err) }
} }
// //
@ -75,7 +75,7 @@ fn testsuite_begin() {
for f in [tmp_file, source_file, output_file, res_original_file, res_changed_file, res_another_file, for f in [tmp_file, source_file, output_file, res_original_file, res_changed_file, res_another_file,
res_stop_file, res_stop_file,
] { ] {
os.rm(f) os.rm(f) or { }
} }
atomic_write_source(live_program_source) atomic_write_source(live_program_source)
} }
@ -105,7 +105,7 @@ fn testsuite_end() {
assert histogram['CHANGED'] + histogram['ANOTHER'] > 0 assert histogram['CHANGED'] + histogram['ANOTHER'] > 0
// assert histogram['END'] > 0 // assert histogram['END'] > 0
for tfile in cleanup_files { for tfile in cleanup_files {
os.rm(tfile) os.rm(tfile) or { }
} }
} }

View File

@ -9,7 +9,10 @@ fn append_to_file(fname string, s string) {
println('>>>> could not open file $fname for appending, err: $err ') println('>>>> could not open file $fname for appending, err: $err ')
return return
} }
f.writeln(s) f.writeln(s) or {
println('>>>> could not write to $fname, err: $err ')
return
}
// info := live.info() // info := live.info()
// f.writeln('>>> reloads: ${info.reloads} | ok reloads: ${info.reloads_ok}') // f.writeln('>>> reloads: ${info.reloads} | ok reloads: ${info.reloads_ok}')
f.close() f.close()
@ -29,6 +32,7 @@ fn pmessage() string {
const ( const (
delay = 20 delay = 20
) )
fn edefault(name string, default string) string { fn edefault(name string, default string) string {
res := os.getenv(name) res := os.getenv(name)
if res == '' { if res == '' {
@ -36,6 +40,7 @@ fn edefault(name string, default string) string {
} }
return res return res
} }
fn main() { fn main() {
mut info := live.info() mut info := live.info()
info.recheck_period_ms = 5 info.recheck_period_ms = 5

View File

@ -112,7 +112,10 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
if op == .decl_assign { if op == .decl_assign {
// a, b := a + 1, b // a, b := a + 1, b
for r in right { for r in right {
p.check_undefined_variables(left, r) p.check_undefined_variables(left, r) or {
p.error('check_undefined_variables failed')
return ast.Stmt{}
}
} }
} else if left.len > 1 { } else if left.len > 1 {
// a, b = b, a // a, b = b, a

View File

@ -94,7 +94,7 @@ pub fn (mut m Main) run() ?string {
res += pcdep.description res += pcdep.description
} }
if pc != 0 { if pc != 0 {
pc.extend(pcdep) pc.extend(pcdep) ?
} else { } else {
pc = pcdep pc = pcdep
} }

View File

@ -155,7 +155,7 @@ fn (mut pc PkgConfig) resolve(pkgname string) ?string {
} }
pub fn atleast(v string) bool { pub fn atleast(v string) bool {
v0 := semver.from(version) or { return false } v0 := semver.from(pkgconfig.version) or { return false }
v1 := semver.from(v) or { return false } v1 := semver.from(v) or { return false }
return v0.gt(v1) return v0.gt(v1)
} }
@ -207,8 +207,8 @@ fn (mut pc PkgConfig) load_require(dep string) ? {
if !pcdep.parse(depfile) { if !pcdep.parse(depfile) {
return error('required file "$depfile" could not be parsed') return error('required file "$depfile" could not be parsed')
} }
pcdep.load_requires() or { return error(err) } pcdep.load_requires() ?
pc.extend(pcdep) pc.extend(pcdep) ?
} }
fn (mut pc PkgConfig) add_path(path string) { fn (mut pc PkgConfig) add_path(path string) {
@ -223,7 +223,7 @@ fn (mut pc PkgConfig) add_path(path string) {
fn (mut pc PkgConfig) load_paths() { fn (mut pc PkgConfig) load_paths() {
if pc.options.use_default_paths { if pc.options.use_default_paths {
for path in default_paths { for path in pkgconfig.default_paths {
pc.add_path(path) pc.add_path(path)
} }
} }

View File

@ -474,10 +474,10 @@ pub fn parse_args(args []string) (&Preferences, string) {
// //
if output_option.len != 0 { if output_option.len != 0 {
res.vrun_elog('remove tmp exe file: $tmp_exe_file_path') res.vrun_elog('remove tmp exe file: $tmp_exe_file_path')
os.rm(tmp_exe_file_path) os.rm(tmp_exe_file_path) or { }
} }
res.vrun_elog('remove tmp v file: $tmp_v_file_path') res.vrun_elog('remove tmp v file: $tmp_v_file_path')
os.rm(tmp_v_file_path) os.rm(tmp_v_file_path) or { panic(err) }
exit(tmp_result) exit(tmp_result)
} }
must_exist(res.path) must_exist(res.path)

View File

@ -33,13 +33,13 @@ fn test_all() {
panic(err) panic(err)
} }
$if windows { $if windows {
os.rm('./test.exe') os.rm('./test.exe') or { }
$if msvc { $if msvc {
os.rm('./test.ilk') os.rm('./test.ilk') or { }
os.rm('./test.pdb') os.rm('./test.pdb') or { }
} }
} $else { } $else {
os.rm('./test') os.rm('./test') or { }
} }
// println('============') // println('============')
// println(res.output) // println(res.output)

View File

@ -64,7 +64,7 @@ fn worker_repl(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
tls_bench.cstep = idx tls_bench.cstep = idx
tfolder := os.join_path(cdir, 'vrepl_tests_$idx') tfolder := os.join_path(cdir, 'vrepl_tests_$idx')
if os.is_dir(tfolder) { if os.is_dir(tfolder) {
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { panic(err) }
} }
os.mkdir(tfolder) or { panic(err) } os.mkdir(tfolder) or { panic(err) }
file := p.get_string_item(idx) file := p.get_string_item(idx)
@ -73,14 +73,14 @@ fn worker_repl(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
fres := runner.run_repl_file(tfolder, session.options.vexec, file) or { fres := runner.run_repl_file(tfolder, session.options.vexec, file) or {
session.bmark.fail() session.bmark.fail()
tls_bench.fail() tls_bench.fail()
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { panic(err) }
eprintln(tls_bench.step_message_fail(err)) eprintln(tls_bench.step_message_fail(err))
assert false assert false
return sync.no_result return sync.no_result
} }
session.bmark.ok() session.bmark.ok()
tls_bench.ok() tls_bench.ok()
os.rmdir_all(tfolder) os.rmdir_all(tfolder) or { panic(err) }
println(tls_bench.step_message_ok(fres)) println(tls_bench.step_message_ok(fres))
assert true assert true
return sync.no_result return sync.no_result

View File

@ -35,37 +35,34 @@ pub fn full_path_to_v(dirs_in int) string {
} }
fn diff_files(file_result string, file_expected string) string { fn diff_files(file_result string, file_expected string) string {
diffcmd := util.find_working_diff_command() or { diffcmd := util.find_working_diff_command() or { return err }
return err
}
return util.color_compare_files(diffcmd, file_result, file_expected) return util.color_compare_files(diffcmd, file_result, file_expected)
} }
pub fn run_repl_file(wd string, vexec string, file string) ?string { pub fn run_repl_file(wd string, vexec string, file string) ?string {
vexec_folder := os.dir(vexec) + os.path_separator vexec_folder := os.dir(vexec) + os.path_separator
fcontent := os.read_file(file) or { fcontent := os.read_file(file) or { return error('Could not read file $file') }
return error('Could not read file $file')
}
content := fcontent.replace('\r', '') content := fcontent.replace('\r', '')
input := content.all_before('===output===\n') input := content.all_before('===output===\n')
output := content.all_after('===output===\n').trim_right('\n\r') output := content.all_after('===output===\n').trim_right('\n\r')
fname := os.file_name(file) fname := os.file_name(file)
input_temporary_filename := os.real_path(os.join_path(wd, 'input_temporary_filename.txt')) input_temporary_filename := os.real_path(os.join_path(wd, 'input_temporary_filename.txt'))
os.write_file(input_temporary_filename, input) os.write_file(input_temporary_filename, input) or { panic(err) }
os.write_file(os.real_path(os.join_path(wd, 'original.txt')), fcontent) os.write_file(os.real_path(os.join_path(wd, 'original.txt')), fcontent) or { panic(err) }
rcmd := '"$vexec" repl -replfolder "$wd" -replprefix "${fname}." < $input_temporary_filename' rcmd := '"$vexec" repl -replfolder "$wd" -replprefix "${fname}." < $input_temporary_filename'
r := os.exec(rcmd) or { r := os.exec(rcmd) or {
os.rm(input_temporary_filename) os.rm(input_temporary_filename) or { panic(err) }
return error('Could not execute: $rcmd') return error('Could not execute: $rcmd')
} }
os.rm(input_temporary_filename) os.rm(input_temporary_filename) or { panic(err) }
result := r.output.replace('\r', '').replace('>>> ', '').replace('>>>', '').replace('... ', result := r.output.replace('\r', '').replace('>>> ', '').replace('>>>', '').replace('... ',
'').replace(wd + os.path_separator, '').replace(vexec_folder, '').replace('\\', '/').trim_right('\n\r') '').replace(wd + os.path_separator, '').replace(vexec_folder, '').replace('\\',
'/').trim_right('\n\r')
if result != output { if result != output {
file_result := '${file}.result.txt' file_result := '${file}.result.txt'
file_expected := '${file}.expected.txt' file_expected := '${file}.expected.txt'
os.write_file(file_result, result) os.write_file(file_result, result) or { panic(err) }
os.write_file(file_expected, output) os.write_file(file_expected, output) or { panic(err) }
diff := diff_files(file_result, file_expected) diff := diff_files(file_result, file_expected)
return error('Difference found in REPL file: $file return error('Difference found in REPL file: $file
====> Got : ====> Got :
@ -87,16 +84,14 @@ pub fn run_prod_file(wd string, vexec string, file string) ?string {
} }
expected_content := f_expected_content.replace('\r', '') expected_content := f_expected_content.replace('\r', '')
cmd := '"$vexec" -prod run "$file"' cmd := '"$vexec" -prod run "$file"'
r := os.exec(cmd) or { r := os.exec(cmd) or { return error('Could not execute: $cmd') }
return error('Could not execute: $cmd')
}
if r.exit_code != 0 { if r.exit_code != 0 {
return error('$cmd return exit code: $r.exit_code') return error('$cmd return exit code: $r.exit_code')
} }
result := r.output.replace('\r', '') result := r.output.replace('\r', '')
if result != expected_content { if result != expected_content {
file_result := '${file}.result.txt' file_result := '${file}.result.txt'
os.write_file(file_result, result) os.write_file(file_result, result) or { panic(err) }
diff := diff_files(file_result, file_expected) diff := diff_files(file_result, file_expected)
return error('Difference found in test: $file return error('Difference found in test: $file
====> Got : ====> Got :

View File

@ -19,7 +19,7 @@ fn pipe_to_v_run() ? {
// eprintln('>> cmd: $cmd | res: $res') // eprintln('>> cmd: $cmd | res: $res')
assert res.exit_code == 0 assert res.exit_code == 0
assert res.output.replace('\r', '').trim_space().split('\n') == ['4', 'hello'] assert res.output.replace('\r', '').trim_space().split('\n') == ['4', 'hello']
os.rm(tmp_v_file) os.rm(tmp_v_file) or { panic(err) }
assert !os.exists(tmp_v_file) assert !os.exists(tmp_v_file)
} }

View File

@ -53,13 +53,11 @@ fn test_all() {
files := os.ls(dir) or { panic(err) } files := os.ls(dir) or { panic(err) }
// //
wrkdir := os.join_path(os.temp_dir(), 'vtests', 'valgrind') wrkdir := os.join_path(os.temp_dir(), 'vtests', 'valgrind')
os.mkdir_all(wrkdir) os.mkdir_all(wrkdir) or { panic(err) }
os.chdir(wrkdir) os.chdir(wrkdir)
// //
tests := vtest.filter_vtest_only(files.filter(it.ends_with('.v') && !it.ends_with('_test.v')), only_ordinary_v_files := files.filter(it.ends_with('.v') && !it.ends_with('_test.v'))
tests := vtest.filter_vtest_only(only_ordinary_v_files, basepath: valgrind_test_path)
basepath: valgrind_test_path
)
bench.set_total_expected_steps(tests.len) bench.set_total_expected_steps(tests.len)
for test in tests { for test in tests {
bench.step() bench.step()

View File

@ -63,10 +63,10 @@ pub fn color_compare_strings(diff_cmd string, expected string, found string) str
ctime := time.sys_mono_now() ctime := time.sys_mono_now()
e_file := os.join_path(cdir, '${ctime}.expected.txt') e_file := os.join_path(cdir, '${ctime}.expected.txt')
f_file := os.join_path(cdir, '${ctime}.found.txt') f_file := os.join_path(cdir, '${ctime}.found.txt')
os.write_file(e_file, expected) os.write_file(e_file, expected) or { panic(err) }
os.write_file(f_file, found) os.write_file(f_file, found) or { panic(err) }
res := color_compare_files(diff_cmd, e_file, f_file) res := color_compare_files(diff_cmd, e_file, f_file)
os.rm(e_file) os.rm(e_file) or { panic(err) }
os.rm(f_file) os.rm(f_file) or { panic(err) }
return res return res
} }

View File

@ -489,7 +489,7 @@ pub fn get_vtmp_folder() string {
} }
vtmp = os.join_path(os.temp_dir(), 'v') vtmp = os.join_path(os.temp_dir(), 'v')
if !os.exists(vtmp) || !os.is_dir(vtmp) { if !os.exists(vtmp) || !os.is_dir(vtmp) {
os.mkdir_all(vtmp) os.mkdir_all(vtmp) or { panic(err) }
} }
os.setenv('VTMP', vtmp, true) os.setenv('VTMP', vtmp, true)
return vtmp return vtmp

View File

@ -40,13 +40,13 @@ pub fn new_cache_manager(opts []string) CacheManager {
vcache_basepath = os.join_path(os.vmodules_dir(), 'cache') vcache_basepath = os.join_path(os.vmodules_dir(), 'cache')
} }
if !os.is_dir(vcache_basepath) { if !os.is_dir(vcache_basepath) {
os.mkdir_all(vcache_basepath) os.mkdir_all(vcache_basepath) or { panic(err) }
readme_content := 'This folder contains cached build artifacts from the V build system. readme_content := 'This folder contains cached build artifacts from the V build system.
|You can safely delete it, if it is getting too large. |You can safely delete it, if it is getting too large.
|It will be recreated the next time you compile something with V. |It will be recreated the next time you compile something with V.
|You can change its location with the VCACHE environment variable. |You can change its location with the VCACHE environment variable.
'.strip_margin() '.strip_margin()
os.write_file(os.join_path(vcache_basepath, 'README.md'), readme_content) os.write_file(os.join_path(vcache_basepath, 'README.md'), readme_content) or { panic(err) }
} }
original_vopts := opts.join('|') original_vopts := opts.join('|')
return CacheManager{ return CacheManager{
@ -74,7 +74,7 @@ pub fn (mut cm CacheManager) key2cpath(key string) string {
cprefix_folder := os.join_path(cm.basepath, prefix) cprefix_folder := os.join_path(cm.basepath, prefix)
cpath = os.join_path(cprefix_folder, khash) cpath = os.join_path(cprefix_folder, khash)
if !os.is_dir(cprefix_folder) { if !os.is_dir(cprefix_folder) {
os.mkdir_all(cprefix_folder) os.mkdir_all(cprefix_folder) or { panic(err) }
os.chmod(cprefix_folder, 0o777) os.chmod(cprefix_folder, 0o777)
} }
cm.k2cpath[key] = cpath cm.k2cpath[key] = cpath

View File

@ -17,7 +17,7 @@ fn check_cache_entry_fpath_invariants(x string, extension string) {
fn testsuite_begin() { fn testsuite_begin() {
os.setenv('VCACHE', vcache_folder, true) os.setenv('VCACHE', vcache_folder, true)
// eprintln('testsuite_begin, vcache_folder = $vcache_folder') // eprintln('testsuite_begin, vcache_folder = $vcache_folder')
os.rmdir_all(vcache_folder) os.rmdir_all(vcache_folder) or { }
vcache.new_cache_manager([]) vcache.new_cache_manager([])
assert os.is_dir(vcache_folder) assert os.is_dir(vcache_folder)
} }
@ -54,33 +54,25 @@ fn test_different_options_should_produce_different_cache_entries_for_same_key_an
fn test_exists() { fn test_exists() {
mut cm := vcache.new_cache_manager([]) mut cm := vcache.new_cache_manager([])
cm.exists('.o', 'abc') or { cm.exists('.o', 'abc') or { assert true }
assert true
}
// //
x := cm.save('.x', 'abc', '') or { x := cm.save('.x', 'abc', '') or {
assert false assert false
'' ''
} }
cm.exists('.o', 'abc') or { cm.exists('.o', 'abc') or { assert true }
assert true
}
// //
y := cm.save('.o', 'zbc', '') or { y := cm.save('.o', 'zbc', '') or {
assert false assert false
'' ''
} }
cm.exists('.o', 'abc') or { cm.exists('.o', 'abc') or { assert true }
assert true
}
// //
z := cm.save('.o', 'abc', '') or { z := cm.save('.o', 'abc', '') or {
assert false assert false
'' ''
} }
cm.exists('.o', 'abc') or { cm.exists('.o', 'abc') or { assert false }
assert false
}
// //
assert os.is_file(x) assert os.is_file(x)
assert os.is_file(y) assert os.is_file(y)
@ -104,6 +96,6 @@ fn test_readme_exists_and_is_readable() {
fn testsuite_end() { fn testsuite_end() {
os.chdir(os.wd_at_startup) os.chdir(os.wd_at_startup)
os.rmdir_all(vcache_folder) os.rmdir_all(vcache_folder) or { }
assert !os.is_dir(vcache_folder) assert !os.is_dir(vcache_folder)
} }

View File

@ -99,7 +99,7 @@ fn (am AssetManager) combine(asset_type string, to_file bool) string {
os.mkdir(am.cache_dir) or { panic(err) } os.mkdir(am.cache_dir) or { panic(err) }
} }
mut file := os.create(out_file) or { panic(err) } mut file := os.create(out_file) or { panic(err) }
file.write(out.bytes()) file.write(out.bytes()) or { panic(err) }
file.close() file.close()
return out_file return out_file
} }

View File

@ -6,7 +6,7 @@ import os
// unique cache dirs are needed per test function. // unique cache dirs are needed per test function.
fn clean_cache_dir(dir string) { fn clean_cache_dir(dir string) {
if os.is_dir(dir) { if os.is_dir(dir) {
os.rmdir_all(dir) os.rmdir_all(dir) or { panic(err) }
} }
} }
@ -21,10 +21,10 @@ fn cache_dir(test_name string) string {
fn get_test_file_path(file string) string { fn get_test_file_path(file string) string {
path := os.join_path(base_cache_dir(), file) path := os.join_path(base_cache_dir(), file)
if !os.is_dir(base_cache_dir()) { if !os.is_dir(base_cache_dir()) {
os.mkdir_all(base_cache_dir()) os.mkdir_all(base_cache_dir()) or { panic(err) }
} }
if !os.exists(path) { if !os.exists(path) {
os.write_file(path, get_test_file_contents(file)) os.write_file(path, get_test_file_contents(file)) or { panic(err) }
} }
return path return path
} }

View File

@ -20,7 +20,7 @@ const (
fn testsuite_begin() { fn testsuite_begin() {
os.chdir(vroot) os.chdir(vroot)
if os.exists(serverexe) { if os.exists(serverexe) {
os.rm(serverexe) os.rm(serverexe) or { }
} }
} }
@ -246,7 +246,7 @@ fn simple_tcp_client(config SimpleTcpClientConfig) ?string {
client.set_read_timeout(tcp_r_timeout) client.set_read_timeout(tcp_r_timeout)
client.set_write_timeout(tcp_w_timeout) client.set_write_timeout(tcp_w_timeout)
defer { defer {
client.close() client.close() or { }
} }
message := 'GET $config.path HTTP/1.1 message := 'GET $config.path HTTP/1.1
Host: $config.host Host: $config.host

View File

@ -355,7 +355,8 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
//} //}
// read body // read body
mut read_body := []byte{len: len} mut read_body := []byte{len: len}
reader.read(mut read_body) // read just the amount of content len if there is no content there is nothing more to read here // read just the amount of content len if there is no content there is nothing more to read here
reader.read(mut read_body) or { println('reader.read failed with err: $err') }
body += read_body.bytestr() body += read_body.bytestr()
break break
} }

View File

@ -1,4 +1,5 @@
module ttf module ttf
/********************************************************************** /**********************************************************************
* *
* Common data for the module * Common data for the module
@ -15,8 +16,7 @@ import os
import math import math
// text align // text align
pub pub enum Text_align {
enum Text_align {
left left
center center
right right
@ -24,8 +24,7 @@ enum Text_align {
} }
// draw style // draw style
pub pub enum Style {
enum Style {
outline outline
outline_aliased outline_aliased
filled filled
@ -38,8 +37,9 @@ enum Style {
* *
******************************************************************************/ ******************************************************************************/
const debug_flag = false const debug_flag = false
fn dprintln(txt string) { fn dprintln(txt string) {
if debug_flag { if ttf.debug_flag {
println(txt) println(txt)
} }
} }
@ -85,8 +85,7 @@ fn (mut bmp BitMap) format_texture(){
} }
// write out a .ppm file // write out a .ppm file
pub pub fn (mut bmp BitMap) save_as_ppm(file_name string) {
fn (mut bmp BitMap) save_as_ppm(file_name string) {
tmp_buf := bmp.buf tmp_buf := bmp.buf
mut buf := malloc(bmp.buf_size) mut buf := malloc(bmp.buf_size)
unsafe { C.memcpy(buf, tmp_buf, bmp.buf_size) } unsafe { C.memcpy(buf, tmp_buf, bmp.buf_size) }
@ -95,18 +94,17 @@ fn (mut bmp BitMap) save_as_ppm(file_name string) {
bmp.format_texture() bmp.format_texture()
npixels := bmp.width * bmp.height npixels := bmp.width * bmp.height
mut f_out := os.create(file_name) or { panic(err) } mut f_out := os.create(file_name) or { panic(err) }
f_out.writeln('P3') f_out.writeln('P3') or { panic(err) }
f_out.writeln('${bmp.width} ${bmp.height}') f_out.writeln('$bmp.width $bmp.height') or { panic(err) }
f_out.writeln('255') f_out.writeln('255') or { panic(err) }
for i in 0 .. npixels { for i in 0 .. npixels {
pos := i * bmp.bp pos := i * bmp.bp
unsafe { unsafe {
c_r := bmp.buf[pos] c_r := bmp.buf[pos]
c_g := bmp.buf[pos + 1] c_g := bmp.buf[pos + 1]
c_b := bmp.buf[pos + 2] c_b := bmp.buf[pos + 2]
f_out.write_str('${c_r} ${c_g} ${c_b} ') f_out.write_str('$c_r $c_g $c_b ') or { panic(err) }
} }
} }
f_out.close() f_out.close()
@ -114,23 +112,22 @@ fn (mut bmp BitMap) save_as_ppm(file_name string) {
bmp.buf = tmp_buf bmp.buf = tmp_buf
} }
pub pub fn (mut bmp BitMap) get_raw_bytes() []byte {
fn (mut bmp BitMap) get_raw_bytes() []byte {
mut f_buf := []byte{len: bmp.buf_size / 4} mut f_buf := []byte{len: bmp.buf_size / 4}
mut i := 0 mut i := 0
for i < bmp.buf_size { for i < bmp.buf_size {
unsafe { f_buf[i>>2] = *(bmp.buf + i) } unsafe {
f_buf[i >> 2] = *(bmp.buf + i)
}
i += 4 i += 4
} }
return f_buf return f_buf
} }
pub pub fn (mut bmp BitMap) save_raw_data(file_name string) {
fn (mut bmp BitMap) save_raw_data(file_name string) { os.write_file_array(file_name, bmp.get_raw_bytes()) or { panic(err) }
os.write_file_array(file_name, bmp.get_raw_bytes())
} }
// //
// Math functions // Math functions
// //
@ -181,8 +178,7 @@ fn rfpart(x f32) f32 {
******************************************************************************/ ******************************************************************************/
/* /*
[inline] [inline]
pub pub fn (mut dev BitMap) get_color(x int, y int) (int, int, int, int){
fn (mut dev BitMap) get_color(x int, y int) (int, int, int, int){
if x < 0 || x >= dev.width || y < 0 || y >= dev.height { if x < 0 || x >= dev.width || y < 0 || y >= dev.height {
return 0,0,0,0 return 0,0,0,0
} }
@ -193,8 +189,7 @@ fn (mut dev BitMap) get_color(x int, y int) (int, int, int, int){
} }
[inline] [inline]
pub pub fn (mut dev BitMap) get_color_u32(x int, y int) u32{
fn (mut dev BitMap) get_color_u32(x int, y int) u32{
r, g, b, a := dev.get_color(x, y) r, g, b, a := dev.get_color(x, y)
unsafe{ unsafe{
return u32(r<<24) | u32(g<<16) | u32(b<<8) | u32(a) return u32(r<<24) | u32(g<<16) | u32(b<<8) | u32(a)
@ -207,14 +202,12 @@ fn (mut dev BitMap) get_color_u32(x int, y int) u32{
* *
******************************************************************************/ ******************************************************************************/
[inline] [inline]
pub pub fn color_multiply_alpha(c u32, level f32) u32 {
fn color_multiply_alpha(c u32, level f32) u32 {
return u32(f32(c & 0xFF) * level) return u32(f32(c & 0xFF) * level)
} }
[inline] [inline]
pub pub fn color_multiply(c u32, level f32) u32 {
fn color_multiply(c u32, level f32) u32 {
mut r := (f32((c >> 24) & 0xFF) / 255.0) * level mut r := (f32((c >> 24) & 0xFF) / 255.0) * level
mut g := (f32((c >> 16) & 0xFF) / 255.0) * level mut g := (f32((c >> 16) & 0xFF) / 255.0) * level
mut b := (f32((c >> 8) & 0xFF) / 255.0) * level mut b := (f32((c >> 8) & 0xFF) / 255.0) * level

View File

@ -1,4 +1,5 @@
module ttf module ttf
/********************************************************************** /**********************************************************************
* *
* BMP render module utility functions * BMP render module utility functions
@ -15,40 +16,31 @@ module ttf
import encoding.utf8 import encoding.utf8
import math import math
pub pub struct BitMap {
struct BitMap {
pub mut: pub mut:
tf &TTF_File tf &TTF_File
buf byteptr // pointer to the memory buffer buf byteptr // pointer to the memory buffer
buf_size int // allocated buf size in bytes buf_size int // allocated buf size in bytes
width int = 1 // width of the buffer width int = 1 // width of the buffer
height int = 1 // height of the buffer height int = 1 // height of the buffer
bp int = 4 // byte per pixel of the buffer bp int = 4 // byte per pixel of the buffer
bg_color u32 = 0xFFFFFF_00 // background RGBA format bg_color u32 = 0xFFFFFF_00 // background RGBA format
color u32 = 0x000000_FF // RGBA format color u32 = 0x000000_FF // RGBA format
scale f32 = 1.0 // internal usage!! scale f32 = 1.0 // internal usage!!
scale_x f32 = 1.0 // X scale of the single glyph scale_x f32 = 1.0 // X scale of the single glyph
scale_y f32 = 1.0 // Y scale of the single glyph scale_y f32 = 1.0 // Y scale of the single glyph
angle f32 = 0.0 // angle of rotation of the bitmap angle f32 = 0.0 // angle of rotation of the bitmap
// spaces // spaces
space_cw f32 = 1.0 // width of the space glyph internal usage!! space_cw f32 = 1.0 // width of the space glyph internal usage!!
space_mult f32 = f32(0.0) // 1.0/16.0 // space between letter, is a multiplier for a standrd space ax space_mult f32 = f32(0.0) // 1.0/16.0 // space between letter, is a multiplier for a standrd space ax
// used only by internal text rendering!! // used only by internal text rendering!!
tr_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // transformation matrix tr_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // transformation matrix
ch_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // character matrix ch_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // character matrix
style Style = .filled // default syle style Style = .filled // default syle
align Text_align = .left // default text align align Text_align = .left // default text align
justify bool // justify text flag, default deactivated justify bool // justify text flag, default deactivated
justify_fill_ratio f32 = 0.5 // justify fill ratio, if the ratio of the filled row is >= of this then justify the text justify_fill_ratio f32 = 0.5 // justify fill ratio, if the ratio of the filled row is >= of this then justify the text
filler [][]int // filler buffer for the renderer filler [][]int // filler buffer for the renderer
// flag to force font embedded metrics // flag to force font embedded metrics
use_font_metrics bool use_font_metrics bool
} }
@ -59,8 +51,7 @@ pub mut:
* *
******************************************************************************/ ******************************************************************************/
// clear clear the bitmap with 0 bytes // clear clear the bitmap with 0 bytes
pub pub fn (mut bmp BitMap) clear() {
fn (mut bmp BitMap) clear() {
mut sz := bmp.width * bmp.height * bmp.bp mut sz := bmp.width * bmp.height * bmp.bp
unsafe { unsafe {
C.memset(bmp.buf, 0x00, sz) C.memset(bmp.buf, 0x00, sz)
@ -69,26 +60,24 @@ fn (mut bmp BitMap) clear() {
// transform matrix applied to the text // transform matrix applied to the text
fn (bmp &BitMap) trf_txt(p &Point) (int, int) { fn (bmp &BitMap) trf_txt(p &Point) (int, int) {
return int(p.x * bmp.tr_matrix[0] + p.y * bmp.tr_matrix[3] + bmp.tr_matrix[6]), return int(p.x * bmp.tr_matrix[0] + p.y * bmp.tr_matrix[3] + bmp.tr_matrix[6]), int(
int(p.x * bmp.tr_matrix[1] + p.y * bmp.tr_matrix[4] + bmp.tr_matrix[7]) p.x * bmp.tr_matrix[1] + p.y * bmp.tr_matrix[4] + bmp.tr_matrix[7])
} }
// transform matrix applied to the char // transform matrix applied to the char
fn (bmp &BitMap) trf_ch(p &Point) (int, int) { fn (bmp &BitMap) trf_ch(p &Point) (int, int) {
return int(p.x * bmp.ch_matrix[0] + p.y * bmp.ch_matrix[3] + bmp.ch_matrix[6]), return int(p.x * bmp.ch_matrix[0] + p.y * bmp.ch_matrix[3] + bmp.ch_matrix[6]), int(
int(p.x * bmp.ch_matrix[1] + p.y * bmp.ch_matrix[4] + bmp.ch_matrix[7]) p.x * bmp.ch_matrix[1] + p.y * bmp.ch_matrix[4] + bmp.ch_matrix[7])
} }
// set draw postion in the buffer // set draw postion in the buffer
pub pub fn (mut bmp BitMap) set_pos(x f32, y f32) {
fn (mut bmp BitMap) set_pos(x f32, y f32) {
bmp.tr_matrix[6] = x bmp.tr_matrix[6] = x
bmp.tr_matrix[7] = y bmp.tr_matrix[7] = y
} }
// set the rotation angle in radiants // set the rotation angle in radiants
pub pub fn (mut bmp BitMap) set_rotation(a f32) {
fn (mut bmp BitMap) set_rotation(a f32) {
bmp.tr_matrix[0] = f32(math.cos(a)) // 1 bmp.tr_matrix[0] = f32(math.cos(a)) // 1
bmp.tr_matrix[1] = f32(-math.sin(a)) // 0 bmp.tr_matrix[1] = f32(-math.sin(a)) // 0
bmp.tr_matrix[3] = f32(math.sin(a)) // 0 bmp.tr_matrix[3] = f32(math.sin(a)) // 0
@ -100,8 +89,7 @@ fn (mut bmp BitMap) set_rotation(a f32) {
* Filler functions * Filler functions
* *
******************************************************************************/ ******************************************************************************/
pub pub fn (mut bmp BitMap) init_filler() {
fn (mut bmp BitMap) init_filler() {
h := bmp.height - bmp.filler.len h := bmp.height - bmp.filler.len
if h < 1 { if h < 1 {
return return
@ -112,15 +100,13 @@ fn (mut bmp BitMap) init_filler() {
// dprintln("Init filler: ${bmp.filler.len} rows") // dprintln("Init filler: ${bmp.filler.len} rows")
} }
pub pub fn (mut bmp BitMap) clear_filler() {
fn (mut bmp BitMap) clear_filler() {
for i in 0 .. bmp.height { for i in 0 .. bmp.height {
bmp.filler[i].clear() bmp.filler[i].clear()
} }
} }
pub pub fn (mut bmp BitMap) exec_filler() {
fn (mut bmp BitMap) exec_filler() {
for y in 0 .. bmp.height { for y in 0 .. bmp.height {
if bmp.filler[y].len > 0 { if bmp.filler[y].len > 0 {
bmp.filler[y].sort() bmp.filler[y].sort()
@ -145,8 +131,7 @@ fn (mut bmp BitMap) exec_filler() {
} }
} }
pub pub fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
mut x0 := f32(in_x0) mut x0 := f32(in_x0)
mut x1 := f32(in_x1) mut x1 := f32(in_x1)
mut y0 := f32(in_y0) mut y0 := f32(in_y0)
@ -203,8 +188,7 @@ fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
* *
******************************************************************************/ ******************************************************************************/
[inline] [inline]
pub pub fn (mut bmp BitMap) plot(x int, y int, c u32) bool {
fn (mut bmp BitMap) plot(x int, y int, c u32) bool {
if x < 0 || x >= bmp.width || y < 0 || y >= bmp.height { if x < 0 || x >= bmp.width || y < 0 || y >= bmp.height {
return false return false
} }
@ -229,8 +213,7 @@ fn (mut bmp BitMap) plot(x int, y int, c u32) bool {
* *
******************************************************************************/ ******************************************************************************/
// aline draw an aliased line on the bitmap // aline draw an aliased line on the bitmap
pub pub fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
// mut c1 := c // mut c1 := c
mut x0 := f32(in_x0) mut x0 := f32(in_x0)
mut x1 := f32(in_x1) mut x1 := f32(in_x1)
@ -280,7 +263,6 @@ fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
x += 1.0 x += 1.0
} }
} else { } else {
if y1 < y0 { if y1 < y0 {
tmp = x0 tmp = x0
@ -325,9 +307,7 @@ fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
* draw functions * draw functions
* *
******************************************************************************/ ******************************************************************************/
pub pub fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
// outline with aliased borders // outline with aliased borders
if bmp.style == .outline_aliased { if bmp.style == .outline_aliased {
bmp.aline(in_x0, in_y0, in_x1, in_y1, c) bmp.aline(in_x0, in_y0, in_x1, in_y1, c)
@ -371,8 +351,8 @@ fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
for yt in y1 .. y0 + 1 { for yt in y1 .. y0 + 1 {
bmp.plot(x0, yt, c) bmp.plot(x0, yt, c)
} }
return
// horizontal line // horizontal line
return
} else if dy == 0 { } else if dy == 0 {
if x0 < x1 { if x0 < x1 {
for xt in x0 .. x1 + 1 { for xt in x0 .. x1 + 1 {
@ -405,20 +385,16 @@ fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
y += sy y += sy
} }
} }
} }
pub fn (mut bmp BitMap) box(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
pub
fn (mut bmp BitMap) box(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
bmp.line(in_x0, in_y0, in_x1, in_y0, c) bmp.line(in_x0, in_y0, in_x1, in_y0, c)
bmp.line(in_x1, in_y0, in_x1, in_y1, c) bmp.line(in_x1, in_y0, in_x1, in_y1, c)
bmp.line(in_x0, in_y1, in_x1, in_y1, c) bmp.line(in_x0, in_y1, in_x1, in_y1, c)
bmp.line(in_x0, in_y0, in_x0, in_y1, c) bmp.line(in_x0, in_y0, in_x0, in_y1, c)
} }
pub pub fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in_cx int, in_cy int, c u32) {
fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in_cx int, in_cy int, c u32) {
/* /*
x0 := int(in_x0 * bmp.scale) x0 := int(in_x0 * bmp.scale)
x1 := int(in_x1 * bmp.scale) x1 := int(in_x1 * bmp.scale)
@ -484,8 +460,7 @@ fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in_cx
* TTF Query functions * TTF Query functions
* *
******************************************************************************/ ******************************************************************************/
pub pub fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
mut res := []int{} mut res := []int{}
mut w := 0 mut w := 0
@ -505,7 +480,6 @@ fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
i++ i++
continue continue
} }
// manage unicode chars like latin greek etc // manage unicode chars like latin greek etc
c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1 c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1
if c_len > 1 { if c_len > 1 {
@ -558,8 +532,7 @@ fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
return res return res
} }
pub pub fn (mut bmp BitMap) get_bbox(in_string string) (int, int) {
fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
mut w := 0 mut w := 0
mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `)) mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `))
@ -578,7 +551,6 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
i++ i++
continue continue
} }
// manage unicode chars like latin greek etc // manage unicode chars like latin greek etc
c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1 c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1
if c_len > 1 { if c_len > 1 {
@ -655,8 +627,7 @@ fn (mut bmp BitMap) draw_notdef_glyph(in_x int, in_w int) {
bmp.line(int(x - in_w), int(y), int(x), int(y - y_h), bmp.color) bmp.line(int(x - in_w), int(y), int(x), int(y - y_h), bmp.color)
} }
pub pub fn (mut bmp BitMap) draw_text(in_string string) (int, int) {
fn (mut bmp BitMap) draw_text(in_string string) (int, int){
mut w := 0 mut w := 0
mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `)) mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `))
@ -675,7 +646,6 @@ fn (mut bmp BitMap) draw_text(in_string string) (int, int){
i++ i++
continue continue
} }
// manage unicode chars like latin greek etc // manage unicode chars like latin greek etc
c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1 c_len := ((0xe5000000 >> ((char >> 3) & 0x1e)) & 3) + 1
if c_len > 1 { if c_len > 1 {
@ -732,8 +702,7 @@ fn (mut bmp BitMap) draw_text(in_string string) (int, int){
return w, int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale) return w, int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
} }
pub pub fn (mut bmp BitMap) draw_glyph(index u16) (int, int) {
fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
glyph := bmp.tf.read_glyph(index) glyph := bmp.tf.read_glyph(index)
if !glyph.valid_glyph { if !glyph.valid_glyph {
@ -781,7 +750,6 @@ fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
} else { } else {
s = 2 s = 2
} }
} else { } else {
// dprintln("s==2") // dprintln("s==2")
mut prev := glyph.points[count - 1] mut prev := glyph.points[count - 1]
@ -803,7 +771,8 @@ fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
// bmp.line(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, color2) // bmp.line(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, color2)
// bmp.quadratic(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, prev.x, prev.y, color2) // bmp.quadratic(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, prev.x, prev.y, color2)
bmp.quadratic(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, prev.x, prev.y, color) bmp.quadratic(x0, y0, (prev.x + point.x) / 2, (prev.y + point.y) / 2,
prev.x, prev.y, color)
x0 = (prev.x + point.x) / 2 x0 = (prev.x + point.x) / 2
y0 = (prev.y + point.y) / 2 y0 = (prev.y + point.y) / 2
} }
@ -820,20 +789,18 @@ fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
// point.x + x, point.y + y); // point.x + x, point.y + y);
// bmp.line(x0, y0, start_point.x + in_x, start_point.y + in_y, u32(0x00FF0000)) // bmp.line(x0, y0, start_point.x + in_x, start_point.y + in_y, u32(0x00FF0000))
bmp.quadratic(x0, y0, start_point.x, start_point.y ,
// start_point.x + in_x, start_point.y + in_y, u32(0xFF00FF00)) // start_point.x + in_x, start_point.y + in_y, u32(0xFF00FF00))
start_point.x, start_point.y, color) bmp.quadratic(x0, y0, start_point.x, start_point.y, start_point.x,
start_point.y, color)
} else { } else {
// ctx.quadraticCurveTo(prev.x + x, prev.y + y, // ctx.quadraticCurveTo(prev.x + x, prev.y + y,
// (prev.x + point.x) / 2 + x, // (prev.x + point.x) / 2 + x,
// (prev.y + point.y) / 2 + y); // (prev.y + point.y) / 2 + y);
// bmp.line(x0, y0, start_point.x, start_point.y, u32(0x00FF0000) // bmp.line(x0, y0, start_point.x, start_point.y, u32(0x00FF0000)
bmp.quadratic(x0, y0, start_point.x, start_point.y,
(point.x + start_point.x)/2,
(point.y + start_point.y)/2,
// u32(0xFF000000)) // u32(0xFF000000))
color) bmp.quadratic(x0, y0, start_point.x, start_point.y, (point.x +
start_point.x) / 2, (point.y + start_point.y) / 2, color)
} }
} else { } else {
// last point not in a curve // last point not in a curve

View File

@ -1,4 +1,5 @@
module ttf module ttf
/********************************************************************** /**********************************************************************
* *
* BMP render module utility functions * BMP render module utility functions
@ -15,11 +16,9 @@ import math
import gg import gg
import sokol.sgl import sokol.sgl
pub pub struct TTF_render_Sokol {
struct TTF_render_Sokol {
pub mut: pub mut:
bmp &BitMap // Base bitmap render bmp &BitMap // Base bitmap render
// rendering fields // rendering fields
sg_img C.sg_image // sokol image sg_img C.sg_image // sokol image
scale_reduct f32 = 2.0 // scale of the cpu texture for filtering scale_reduct f32 = 2.0 // scale of the cpu texture for filtering
@ -35,8 +34,7 @@ fn (mut tf_skl TTF_render_Sokol) format_texture(){
tf_skl.bmp.format_texture() tf_skl.bmp.format_texture()
} }
pub pub fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32) {
fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32){
scale_reduct := tf_skl.scale_reduct scale_reduct := tf_skl.scale_reduct
device_dpi := tf_skl.device_dpi device_dpi := tf_skl.device_dpi
font_size := in_font_size //* scale_reduct font_size := in_font_size //* scale_reduct
@ -57,7 +55,7 @@ fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32){
if sz > 0 { if sz > 0 {
free(tf_skl.bmp.buf) free(tf_skl.bmp.buf)
} }
dprintln("create_text Alloc: $sz bytes") dprintln('create_text Alloc: $sz bytes')
tf_skl.bmp.buf = malloc(sz) tf_skl.bmp.buf = malloc(sz)
tf_skl.bmp.buf_size = sz tf_skl.bmp.buf_size = sz
} }
@ -72,8 +70,7 @@ fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32){
tf_skl.format_texture() tf_skl.format_texture()
} }
pub pub fn (mut tf_skl TTF_render_Sokol) create_text_block(in_txt string, in_w int, in_h int, in_font_size f32) {
fn (mut tf_skl TTF_render_Sokol) create_text_block(in_txt string, in_w int, in_h int, in_font_size f32){
scale_reduct := tf_skl.scale_reduct scale_reduct := tf_skl.scale_reduct
device_dpi := tf_skl.device_dpi device_dpi := tf_skl.device_dpi
font_size := in_font_size //* scale_reduct font_size := in_font_size //* scale_reduct
@ -96,7 +93,7 @@ fn (mut tf_skl TTF_render_Sokol) create_text_block(in_txt string, in_w int, in_h
if sz > 0 { if sz > 0 {
free(tf_skl.bmp.buf) free(tf_skl.bmp.buf)
} }
dprintln("Alloc: $sz bytes") dprintln('Alloc: $sz bytes')
tf_skl.bmp.buf = malloc(sz) tf_skl.bmp.buf = malloc(sz)
tf_skl.bmp.buf_size = sz tf_skl.bmp.buf_size = sz
} }
@ -108,16 +105,16 @@ fn (mut tf_skl TTF_render_Sokol) create_text_block(in_txt string, in_w int, in_h
tf_skl.bmp.set_pos(0, y_base) tf_skl.bmp.set_pos(0, y_base)
tf_skl.bmp.clear() tf_skl.bmp.clear()
tf_skl.bmp.draw_text_block(in_txt, {x: 0, y:0, w:w, h:h}) tf_skl.bmp.draw_text_block(in_txt, x: 0, y: 0, w: w, h: h)
tf_skl.format_texture() tf_skl.format_texture()
} }
/****************************************************************************** /******************************************************************************
* *
* Sokol Render functions * Sokol Render functions
* *
******************************************************************************/ ******************************************************************************/
pub pub fn (mut tf_skl TTF_render_Sokol) create_texture() {
fn (mut tf_skl TTF_render_Sokol) create_texture(){
w := tf_skl.bmp.width w := tf_skl.bmp.width
h := tf_skl.bmp.height h := tf_skl.bmp.height
sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp
@ -144,14 +141,12 @@ fn (mut tf_skl TTF_render_Sokol) create_texture(){
tf_skl.sg_img = simg tf_skl.sg_img = simg
} }
pub pub fn (tf_skl TTF_render_Sokol) destroy_texture() {
fn (tf_skl TTF_render_Sokol) destroy_texture(){
C.sg_destroy_image(tf_skl.sg_img) C.sg_destroy_image(tf_skl.sg_img)
} }
// Use only if usage: .dynamic // Use only if usage: .dynamic
pub pub fn (mut tf_skl TTF_render_Sokol) update_text_texture() {
fn (mut tf_skl TTF_render_Sokol) update_text_texture(){
sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp
mut tmp_sbc := C.sg_image_content{} mut tmp_sbc := C.sg_image_content{}
tmp_sbc.subimage[0][0] = C.sg_subimage_content{ tmp_sbc.subimage[0][0] = C.sg_subimage_content{
@ -161,8 +156,7 @@ fn (mut tf_skl TTF_render_Sokol) update_text_texture(){
C.sg_update_image(tf_skl.sg_img, &tmp_sbc) C.sg_update_image(tf_skl.sg_img, &tmp_sbc)
} }
pub pub fn (tf_skl TTF_render_Sokol) draw_text_bmp(ctx &gg.Context, x f32, y f32) {
fn (tf_skl TTF_render_Sokol) draw_text_bmp(ctx &gg.Context, x f32, y f32) {
// width := tf_skl.bmp.width >> 1 // width := tf_skl.bmp.width >> 1
// height := tf_skl.bmp.height >> 1 // height := tf_skl.bmp.height >> 1
sgl.push_matrix() sgl.push_matrix()
@ -182,10 +176,22 @@ fn (tf_skl TTF_render_Sokol) draw_text_bmp(ctx &gg.Context, x f32, y f32) {
ca := f32(math.cos(tf_skl.bmp.angle)) ca := f32(math.cos(tf_skl.bmp.angle))
sa := f32(math.sin(tf_skl.bmp.angle)) sa := f32(math.sin(tf_skl.bmp.angle))
m := [ m := [
f32(ca),-sa,0,0, f32(ca),
sa,ca,0,0, -sa,
0,0,1,0, 0,
x,y,0,1 0,
sa,
ca,
0,
0,
0,
0,
1,
0,
x,
y,
0,
1,
] ]
sgl.mult_matrix(m) sgl.mult_matrix(m)
// //

View File

@ -1,4 +1,5 @@
module ttf module ttf
/********************************************************************** /**********************************************************************
* *
* BMP render module utility functions * BMP render module utility functions
@ -11,8 +12,7 @@ module ttf
* *
* TODO: * TODO:
**********************************************************************/ **********************************************************************/
pub pub struct Text_block {
struct Text_block {
x int // x postion of the left high corner x int // x postion of the left high corner
y int // y postion of the left high corner y int // y postion of the left high corner
w int // width of the text block w int // width of the text block
@ -21,7 +21,7 @@ struct Text_block {
} }
fn (mut dev BitMap) get_justify_space_cw(txt string, w int, block_w int, space_cw int) f32 { fn (mut dev BitMap) get_justify_space_cw(txt string, w int, block_w int, space_cw int) f32 {
num_spaces := txt.count(" ") num_spaces := txt.count(' ')
if num_spaces < 1 { if num_spaces < 1 {
return 0 return 0
} }
@ -34,8 +34,7 @@ fn (mut dev BitMap) get_justify_space_cw(txt string, w int, block_w int, space_c
} }
// write out a text // write out a text
pub pub fn (mut bmp BitMap) draw_text_block(text string, block Text_block) {
fn (mut bmp BitMap) draw_text_block(text string, block Text_block) {
mut x := block.x mut x := block.x
mut y := block.y mut y := block.y
mut y_base := int((bmp.tf.y_max - bmp.tf.y_min) * bmp.scale) mut y_base := int((bmp.tf.y_max - bmp.tf.y_min) * bmp.scale)
@ -73,7 +72,7 @@ fn (mut bmp BitMap) draw_text_block(text string, block Text_block) {
y += y_base y += y_base
} else { } else {
// println("to cut: ${txt}") // println("to cut: ${txt}")
mut txt1 := txt.split(" ") mut txt1 := txt.split(' ')
mut c := txt1.len mut c := txt1.len
// mut done := false // mut done := false
for c > 0 { for c > 0 {

View File

@ -1,4 +1,5 @@
module ttf module ttf
/********************************************************************** /**********************************************************************
* *
* TrueTypeFont reader V implementation * TrueTypeFont reader V implementation
@ -16,7 +17,6 @@ module ttf
**********************************************************************/ **********************************************************************/
import strings import strings
/****************************************************************************** /******************************************************************************
* *
* CMAP structs * CMAP structs
@ -43,21 +43,16 @@ mut:
* TTF_File structs * TTF_File structs
* *
******************************************************************************/ ******************************************************************************/
pub pub struct TTF_File {
struct TTF_File{
pub mut: pub mut:
buf []byte buf []byte
pos u32 pos u32
length u16 length u16
scalar_type u32 scalar_type u32
search_range u16 search_range u16
entry_selector u16 entry_selector u16
range_shift u16 range_shift u16
tables map[string]Offset_Table tables map[string]Offset_Table
version f32 version f32
font_revision f32 font_revision f32
checksum_adjustment u32 checksum_adjustment u32
@ -75,14 +70,11 @@ pub mut:
font_direction_hint i16 font_direction_hint i16
index_to_loc_format i16 index_to_loc_format i16
glyph_data_format i16 glyph_data_format i16
font_family string font_family string
font_sub_family string font_sub_family string
full_name string full_name string
postscript_name string postscript_name string
cmaps []TrueTypeCmap cmaps []TrueTypeCmap
ascent i16 ascent i16
descent i16 descent i16
line_gap i16 line_gap i16
@ -95,15 +87,12 @@ pub mut:
caret_offset i16 caret_offset i16
metric_data_format i16 metric_data_format i16
num_of_long_hor_metrics u16 num_of_long_hor_metrics u16
kern []Kern0Table kern []Kern0Table
// cache // cache
glyph_cache map[int]Glyph glyph_cache map[int]Glyph
} }
pub pub fn (mut tf TTF_File) init() {
fn (mut tf TTF_File) init() {
tf.read_offset_tables() tf.read_offset_tables()
tf.read_head_table() tf.read_head_table()
// dprintln(tf.get_info_string()) // dprintln(tf.get_info_string())
@ -112,17 +101,16 @@ fn (mut tf TTF_File) init() {
tf.read_hhea_table() tf.read_hhea_table()
tf.read_kern_table() tf.read_kern_table()
tf.length = tf.glyph_count() tf.length = tf.glyph_count()
dprintln("Number of symbols: $tf.length") dprintln('Number of symbols: $tf.length')
dprintln("*****************************") dprintln('*****************************')
} }
/****************************************************************************** /******************************************************************************
* *
* TTF_File Glyph Structs * TTF_File Glyph Structs
* *
******************************************************************************/ ******************************************************************************/
pub struct Point {
pub
struct Point {
pub mut: pub mut:
x int x int
y int y int
@ -140,10 +128,9 @@ const(
g_type_complex = u16(2) // compound type g_type_complex = u16(2) // compound type
) )
pub pub struct Glyph {
struct Glyph {
pub mut: pub mut:
g_type u16 = g_type_simple g_type u16 = ttf.g_type_simple
contour_ends []u16 contour_ends []u16
number_of_contours i16 number_of_contours i16
points []Point points []Point
@ -155,17 +142,15 @@ pub mut:
components []Component components []Component
} }
/****************************************************************************** /******************************************************************************
* *
* TTF_File metrics and glyph * TTF_File metrics and glyph
* *
******************************************************************************/ ******************************************************************************/
pub pub fn (mut tf TTF_File) get_horizontal_metrics(glyph_index u16) (int, int) {
fn (mut tf TTF_File) get_horizontal_metrics(glyph_index u16) (int, int) { assert 'hmtx' in tf.tables
assert"hmtx" in tf.tables
old_pos := tf.pos old_pos := tf.pos
mut offset := tf.tables["hmtx"].offset mut offset := tf.tables['hmtx'].offset
mut advance_width := 0 mut advance_width := 0
mut left_side_bearing := 0 mut left_side_bearing := 0
@ -179,7 +164,8 @@ fn (mut tf TTF_File) get_horizontal_metrics(glyph_index u16) (int, int) {
// read the last entry of the hMetrics array // read the last entry of the hMetrics array
tf.pos = offset + (tf.num_of_long_hor_metrics - 1) * 4 tf.pos = offset + (tf.num_of_long_hor_metrics - 1) * 4
advance_width = tf.get_u16() advance_width = tf.get_u16()
tf.pos = offset + tf.num_of_long_hor_metrics * 4 + 2 * (glyph_index - tf.num_of_long_hor_metrics) tf.pos = offset + tf.num_of_long_hor_metrics * 4 +
2 * (glyph_index - tf.num_of_long_hor_metrics)
left_side_bearing = tf.get_fword() left_side_bearing = tf.get_fword()
} }
tf.pos = old_pos tf.pos = old_pos
@ -188,11 +174,11 @@ fn (mut tf TTF_File) get_horizontal_metrics(glyph_index u16) (int, int) {
fn (mut tf TTF_File) get_glyph_offset(index u32) u32 { fn (mut tf TTF_File) get_glyph_offset(index u32) u32 {
// check if needed tables exists // check if needed tables exists
assert "loca" in tf.tables assert 'loca' in tf.tables
assert "glyf" in tf.tables assert 'glyf' in tf.tables
mut old_pos := tf.pos mut old_pos := tf.pos
table := tf.tables["loca"] table := tf.tables['loca']
mut offset := u32(0) mut offset := u32(0)
mut next := u32(0) mut next := u32(0)
if tf.index_to_loc_format == 1 { if tf.index_to_loc_format == 1 {
@ -209,37 +195,36 @@ fn (mut tf TTF_File) get_glyph_offset(index u32) u32{
// indicates glyph has no outline( eg space) // indicates glyph has no outline( eg space)
return 0 return 0
} }
// dprintln("Offset for glyph index $index is $offset") // dprintln("Offset for glyph index $index is $offset")
tf.pos = old_pos tf.pos = old_pos
return offset + tf.tables['glyf'].offset return offset + tf.tables['glyf'].offset
} }
fn (mut tf TTF_File) glyph_count() u16 { fn (mut tf TTF_File) glyph_count() u16 {
assert "maxp" in tf.tables assert 'maxp' in tf.tables
old_pos := tf.pos old_pos := tf.pos
tf.pos = tf.tables["maxp"].offset + 4 tf.pos = tf.tables['maxp'].offset + 4
count := tf.get_u16() count := tf.get_u16()
tf.pos = old_pos tf.pos = old_pos
return count return count
} }
pub pub fn (mut tf TTF_File) read_glyph_dim(index u16) (int, int, int, int) {
fn (mut tf TTF_File) read_glyph_dim(index u16) (int, int, int, int) {
offset := tf.get_glyph_offset(index) offset := tf.get_glyph_offset(index)
// dprintln("offset: $offset") // dprintln("offset: $offset")
if offset == 0 || offset >= tf.tables["glyf"].offset + tf.tables["glyf"].length { if offset == 0 || offset >= tf.tables['glyf'].offset + tf.tables['glyf'].length {
dprintln("No glyph found!") dprintln('No glyph found!')
return 0, 0, 0, 0 return 0, 0, 0, 0
} }
assert offset >= tf.tables["glyf"].offset assert offset >= tf.tables['glyf'].offset
assert offset < tf.tables["glyf"].offset + tf.tables["glyf"].length assert offset < tf.tables['glyf'].offset + tf.tables['glyf'].length
tf.pos = offset tf.pos = offset
// dprintln("file seek read_glyph: $tf.pos") // dprintln("file seek read_glyph: $tf.pos")
/*number_of_contours*/ _ := tf.get_i16() // number_of_contours
_ := tf.get_i16()
x_min := tf.get_fword() x_min := tf.get_fword()
y_min := tf.get_fword() y_min := tf.get_fword()
x_max := tf.get_fword() x_max := tf.get_fword()
@ -248,8 +233,7 @@ fn (mut tf TTF_File) read_glyph_dim(index u16) (int, int, int, int) {
return x_min, x_max, y_min, y_max return x_min, x_max, y_min, y_max
} }
pub pub fn (mut tf TTF_File) read_glyph(index u16) Glyph {
fn (mut tf TTF_File) read_glyph(index u16) Glyph {
index_int := int(index) // index.str() index_int := int(index) // index.str()
if index_int in tf.glyph_cache { if index_int in tf.glyph_cache {
// dprintln("Found glyp: ${index}") // dprintln("Found glyp: ${index}")
@ -259,18 +243,19 @@ fn (mut tf TTF_File) read_glyph(index u16) Glyph {
offset := tf.get_glyph_offset(index) offset := tf.get_glyph_offset(index)
// dprintln("offset: $offset") // dprintln("offset: $offset")
if offset == 0 || offset >= tf.tables["glyf"].offset + tf.tables["glyf"].length { if offset == 0 || offset >= tf.tables['glyf'].offset + tf.tables['glyf'].length {
dprintln("No glyph found!") dprintln('No glyph found!')
return Glyph{} return Glyph{}
} }
assert offset >= tf.tables["glyf"].offset assert offset >= tf.tables['glyf'].offset
assert offset < tf.tables["glyf"].offset + tf.tables["glyf"].length assert offset < tf.tables['glyf'].offset + tf.tables['glyf'].length
tf.pos = offset tf.pos = offset
// dprintln("file seek read_glyph: $tf.pos") // dprintln("file seek read_glyph: $tf.pos")
/* ---- BUG TO SOLVE ----- /*
---- BUG TO SOLVE -----
--- Order of the data if printed in the main is shuffled!! Very Strange --- Order of the data if printed in the main is shuffled!! Very Strange
mut tmp_glyph := Glyph{ mut tmp_glyph := Glyph{
number_of_contours : tf.get_i16() number_of_contours : tf.get_i16()
@ -341,10 +326,9 @@ fn (mut tf TTF_File) read_simple_glyph(mut in_glyph Glyph){
in_glyph.points << Point{ in_glyph.points << Point{
x: 0 x: 0
y: 0 y: 0
on_curve: (flag & tfk_on_curve) > 0 on_curve: (flag & ttf.tfk_on_curve) > 0
} }
if (flag & ttf.tfk_repeat) > 0 {
if (flag & tfk_repeat) > 0 {
mut repeat_count := tf.get_u8() mut repeat_count := tf.get_u8()
assert repeat_count > 0 assert repeat_count > 0
i += repeat_count i += repeat_count
@ -353,7 +337,7 @@ fn (mut tf TTF_File) read_simple_glyph(mut in_glyph Glyph){
in_glyph.points << Point{ in_glyph.points << Point{
x: 0 x: 0
y: 0 y: 0
on_curve: (flag & tfk_on_curve) > 0 on_curve: (flag & ttf.tfk_on_curve) > 0
} }
repeat_count-- repeat_count--
} }
@ -365,13 +349,13 @@ fn (mut tf TTF_File) read_simple_glyph(mut in_glyph Glyph){
mut value := 0 mut value := 0
for i_x in 0 .. num_points { for i_x in 0 .. num_points {
flag_x := flags[i_x] flag_x := flags[i_x]
if (flag_x & tfk_x_is_byte) > 0 { if (flag_x & ttf.tfk_x_is_byte) > 0 {
if (flag_x & tfk_x_delta) > 0 { if (flag_x & ttf.tfk_x_delta) > 0 {
value += tf.get_u8() value += tf.get_u8()
} else { } else {
value -= tf.get_u8() value -= tf.get_u8()
} }
} else if (~flag_x & tfk_x_delta) > 0 { } else if (~flag_x & ttf.tfk_x_delta) > 0 {
value += tf.get_i16() value += tf.get_i16()
} else { } else {
// value is unchanged // value is unchanged
@ -384,13 +368,13 @@ fn (mut tf TTF_File) read_simple_glyph(mut in_glyph Glyph){
value = 0 value = 0
for i_y in 0 .. num_points { for i_y in 0 .. num_points {
flag_y := flags[i_y] flag_y := flags[i_y]
if (flag_y & tfk_y_is_byte) > 0 { if (flag_y & ttf.tfk_y_is_byte) > 0 {
if (flag_y & tfk_y_delta) > 0 { if (flag_y & ttf.tfk_y_delta) > 0 {
value += tf.get_u8() value += tf.get_u8()
} else { } else {
value -= tf.get_u8() value -= tf.get_u8()
} }
} else if (~flag_y & tfk_y_delta) > 0 { } else if (~flag_y & ttf.tfk_y_delta) > 0 {
value += tf.get_i16() value += tf.get_i16()
} else { } else {
// value is unchanged // value is unchanged
@ -426,10 +410,10 @@ mut:
} }
fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph) { fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph) {
in_glyph.g_type = g_type_complex in_glyph.g_type = ttf.g_type_complex
mut component := Component{} mut component := Component{}
mut flags := tfkc_more_components mut flags := ttf.tfkc_more_components
for (flags & tfkc_more_components) > 0 { for (flags & ttf.tfkc_more_components) > 0 {
mut arg1 := i16(0) mut arg1 := i16(0)
mut arg2 := i16(0) mut arg2 := i16(0)
@ -437,7 +421,7 @@ fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph){
component.glyph_index = tf.get_u16() component.glyph_index = tf.get_u16()
if (flags & tfkc_arg_1_and_2_are_words) > 0 { if (flags & ttf.tfkc_arg_1_and_2_are_words) > 0 {
arg1 = tf.get_i16() arg1 = tf.get_i16()
arg2 = tf.get_i16() arg2 = tf.get_i16()
} else { } else {
@ -445,7 +429,7 @@ fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph){
arg2 = tf.get_u8() arg2 = tf.get_u8()
} }
if (flags & tfkc_args_are_xy_values) > 0 { if (flags & ttf.tfkc_args_are_xy_values) > 0 {
component.matrix[4] = arg1 component.matrix[4] = arg1
component.matrix[5] = arg2 component.matrix[5] = arg2
} else { } else {
@ -453,19 +437,18 @@ fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph){
component.src_point_index = arg2 component.src_point_index = arg2
} }
if (flags & tfkc_we_have_a_scale) > 0 { if (flags & ttf.tfkc_we_have_a_scale) > 0 {
component.matrix[0] = tf.get_2dot14() component.matrix[0] = tf.get_2dot14()
component.matrix[3] = component.matrix[0] component.matrix[3] = component.matrix[0]
} else if (flags & tfkc_we_have_an_x_and_y_scale) > 0 { } else if (flags & ttf.tfkc_we_have_an_x_and_y_scale) > 0 {
component.matrix[0] = tf.get_2dot14() component.matrix[0] = tf.get_2dot14()
component.matrix[3] = tf.get_2dot14() component.matrix[3] = tf.get_2dot14()
} else if (flags & tfkc_we_have_a_two_by_two) > 0 { } else if (flags & ttf.tfkc_we_have_a_two_by_two) > 0 {
component.matrix[0] = tf.get_2dot14() component.matrix[0] = tf.get_2dot14()
component.matrix[1] = tf.get_2dot14() component.matrix[1] = tf.get_2dot14()
component.matrix[2] = tf.get_2dot14() component.matrix[2] = tf.get_2dot14()
component.matrix[3] = tf.get_2dot14() component.matrix[3] = tf.get_2dot14()
} }
// dprintln("Read component glyph index ${component.glyph_index}") // dprintln("Read component glyph index ${component.glyph_index}")
// dprintln("Transform: ${component.matrix}") // dprintln("Transform: ${component.matrix}")
@ -495,10 +478,9 @@ fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph){
in_glyph.number_of_contours = i16(in_glyph.contour_ends.len) in_glyph.number_of_contours = i16(in_glyph.contour_ends.len)
if (flags & tfkc_we_have_instructions) > 0 { if (flags & ttf.tfkc_we_have_instructions) > 0 {
tf.pos = tf.get_u16() + tf.pos tf.pos = tf.get_u16() + tf.pos
} }
// ok we have a valid glyph // ok we have a valid glyph
in_glyph.valid_glyph = true in_glyph.valid_glyph = true
} }
@ -537,10 +519,8 @@ fn (mut tf TTF_File) get_fword() i16 {
} }
fn (mut tf TTF_File) get_u32() u32 { fn (mut tf TTF_File) get_u32() u32 {
x :=(u32(tf.buf[tf.pos]) << u32(24)) | x := (u32(tf.buf[tf.pos]) << u32(24)) | (u32(tf.buf[tf.pos +
(u32(tf.buf[tf.pos + 1]) << u32(16)) | 1]) << u32(16)) | (u32(tf.buf[tf.pos + 2]) << u32(8)) | u32(tf.buf[tf.pos + 3])
(u32(tf.buf[tf.pos + 2]) << u32(8)) |
u32(tf.buf[tf.pos + 3])
tf.pos += 4 tf.pos += 4
return x return x
} }
@ -619,7 +599,7 @@ mut:
} }
fn (mut tf TTF_File) read_offset_tables() { fn (mut tf TTF_File) read_offset_tables() {
dprintln("*** READ TABLES OFFSET ***") dprintln('*** READ TABLES OFFSET ***')
tf.pos = 0 tf.pos = 0
tf.scalar_type = tf.get_u32() tf.scalar_type = tf.get_u32()
num_tables := tf.get_u16() num_tables := tf.get_u16()
@ -627,11 +607,11 @@ fn (mut tf TTF_File) read_offset_tables() {
tf.entry_selector = tf.get_u16() tf.entry_selector = tf.get_u16()
tf.range_shift = tf.get_u16() tf.range_shift = tf.get_u16()
dprintln("scalar_type : [0x$tf.scalar_type.hex()]") dprintln('scalar_type : [0x$tf.scalar_type.hex()]')
dprintln("num tables : [$num_tables]") dprintln('num tables : [$num_tables]')
dprintln("search_range : [0x$tf.search_range.hex()]") dprintln('search_range : [0x$tf.search_range.hex()]')
dprintln("entry_selector: [0x$tf.entry_selector.hex()]") dprintln('entry_selector: [0x$tf.entry_selector.hex()]')
dprintln("range_shift : [0x$tf.range_shift.hex()]") dprintln('range_shift : [0x$tf.range_shift.hex()]')
mut i := 0 mut i := 0
for i < num_tables { for i < num_tables {
@ -641,7 +621,7 @@ fn (mut tf TTF_File) read_offset_tables() {
offset: tf.get_u32() offset: tf.get_u32()
length: tf.get_u32() length: tf.get_u32()
} }
dprintln("Table: [$tag]") dprintln('Table: [$tag]')
// dprintln("${tf.tables[tag]}") // dprintln("${tf.tables[tag]}")
if tag != 'head' { if tag != 'head' {
@ -649,7 +629,7 @@ fn (mut tf TTF_File) read_offset_tables() {
} }
i++ i++
} }
dprintln("*** END READ TABLES OFFSET ***") dprintln('*** END READ TABLES OFFSET ***')
} }
/****************************************************************************** /******************************************************************************
@ -658,9 +638,9 @@ fn (mut tf TTF_File) read_offset_tables() {
* *
******************************************************************************/ ******************************************************************************/
fn (mut tf TTF_File) read_head_table() { fn (mut tf TTF_File) read_head_table() {
dprintln("*** READ HEAD TABLE ***") dprintln('*** READ HEAD TABLE ***')
tf.pos = tf.tables["head"].offset tf.pos = tf.tables['head'].offset
dprintln("Offset: $tf.pos") dprintln('Offset: $tf.pos')
tf.version = tf.get_fixed() tf.version = tf.get_fixed()
tf.font_revision = tf.get_fixed() tf.font_revision = tf.get_fixed()
@ -688,10 +668,10 @@ fn (mut tf TTF_File) read_head_table() {
* *
******************************************************************************/ ******************************************************************************/
fn (mut tf TTF_File) read_name_table() { fn (mut tf TTF_File) read_name_table() {
dprintln("*** READ NAME TABLE ***") dprintln('*** READ NAME TABLE ***')
assert "name" in tf.tables assert 'name' in tf.tables
table_offset := tf.tables["name"].offset table_offset := tf.tables['name'].offset
tf.pos = tf.tables["name"].offset tf.pos = tf.tables['name'].offset
format := tf.get_u16() // must be 0 format := tf.get_u16() // must be 0
assert format == 0 assert format == 0
@ -700,8 +680,10 @@ fn (mut tf TTF_File) read_name_table() {
for _ in 0 .. count { for _ in 0 .. count {
platform_id := tf.get_u16() platform_id := tf.get_u16()
/*platform_specific_id :=*/ tf.get_u16() // platform_specific_id :=
/*language_id :=*/ tf.get_u16() tf.get_u16()
// language_id :=
tf.get_u16()
name_id := tf.get_u16() name_id := tf.get_u16()
length := tf.get_u16() length := tf.get_u16()
offset := tf.get_u16() offset := tf.get_u16()
@ -709,7 +691,7 @@ fn (mut tf TTF_File) read_name_table() {
old_pos := tf.pos old_pos := tf.pos
tf.pos = table_offset + string_offset + offset tf.pos = table_offset + string_offset + offset
mut name := "" mut name := ''
if platform_id == 0 || platform_id == 3 { if platform_id == 0 || platform_id == 3 {
name = tf.get_unicode_string(length) name = tf.get_unicode_string(length)
} else { } else {
@ -719,18 +701,10 @@ fn (mut tf TTF_File) read_name_table() {
tf.pos = old_pos tf.pos = old_pos
match name_id { match name_id {
1 { 1 { tf.font_family = name }
tf.font_family = name 2 { tf.font_sub_family = name }
} 4 { tf.full_name = name }
2 { 6 { tf.postscript_name = name }
tf.font_sub_family = name
}
4 {
tf.full_name = name
}
6 {
tf.postscript_name = name
}
else {} else {}
} }
} }
@ -742,9 +716,9 @@ fn (mut tf TTF_File) read_name_table() {
* *
******************************************************************************/ ******************************************************************************/
fn (mut tf TTF_File) read_cmap_table() { fn (mut tf TTF_File) read_cmap_table() {
dprintln("*** READ CMAP TABLE ***") dprintln('*** READ CMAP TABLE ***')
assert "cmap" in tf.tables assert 'cmap' in tf.tables
table_offset := tf.tables["cmap"].offset table_offset := tf.tables['cmap'].offset
tf.pos = table_offset tf.pos = table_offset
version := tf.get_u16() // must be 0 version := tf.get_u16() // must be 0
@ -762,7 +736,7 @@ fn (mut tf TTF_File) read_cmap_table() {
platform_id := tf.get_u16() platform_id := tf.get_u16()
platform_specific_id := tf.get_u16() platform_specific_id := tf.get_u16()
offset := tf.get_u32() offset := tf.get_u32()
dprintln("CMap platform_id=${platform_id} specific_id=${platform_specific_id} offset=${offset}") dprintln('CMap platform_id=$platform_id specific_id=$platform_specific_id offset=$offset')
if platform_id == 3 && platform_specific_id <= 1 { if platform_id == 3 && platform_specific_id <= 1 {
tf.read_cmap(table_offset + offset) tf.read_cmap(table_offset + offset)
} }
@ -776,14 +750,14 @@ fn (mut tf TTF_File) read_cmap(offset u32) {
length := tf.get_u16() length := tf.get_u16()
language := tf.get_u16() language := tf.get_u16()
dprintln(" Cmap format: $format length: $length language: $language") dprintln(' Cmap format: $format length: $length language: $language')
if format == 0 { if format == 0 {
dprintln(" Cmap 0 Init...") dprintln(' Cmap 0 Init...')
mut cmap := TrueTypeCmap{} mut cmap := TrueTypeCmap{}
cmap.init_0(mut tf) cmap.init_0(mut tf)
tf.cmaps << cmap tf.cmaps << cmap
} else if format == 4 { } else if format == 4 {
dprintln(" Cmap 4 Init...") dprintln(' Cmap 4 Init...')
mut cmap := TrueTypeCmap{} mut cmap := TrueTypeCmap{}
cmap.init_4(mut tf) cmap.init_4(mut tf)
tf.cmaps << cmap tf.cmaps << cmap
@ -816,7 +790,7 @@ fn (mut tm TrueTypeCmap) init_0(mut tf TTF_File) {
tm.format = 0 tm.format = 0
for i in 0 .. 256 { for i in 0 .. 256 {
glyph_index := tf.get_u8() glyph_index := tf.get_u8()
dprintln(" Glyph[$i] = %glyph_index") dprintln(' Glyph[$i] = %glyph_index')
tm.arr << glyph_index tm.arr << glyph_index
} }
} }
@ -834,10 +808,12 @@ fn (mut tm TrueTypeCmap) init_4(mut tf TTF_File) {
// 2x segcount // 2x segcount
seg_count := tf.get_u16() >> 1 seg_count := tf.get_u16() >> 1
/*search_range :=*/ tf.get_u16() // search_range :=
/*entry_selector :=*/ tf.get_u16() tf.get_u16()
/*range_shift :=*/ tf.get_u16() // entry_selector :=
tf.get_u16()
// range_shift :=
tf.get_u16()
// Ending character code for each segment, last is 0xffff // Ending character code for each segment, last is 0xffff
for _ in 0 .. seg_count { for _ in 0 .. seg_count {
@ -885,7 +861,8 @@ fn (mut tm TrueTypeCmap) map_4(char_code int, mut tf TTF_File) int {
if segment.start_code <= char_code && segment.end_code >= char_code { if segment.start_code <= char_code && segment.end_code >= char_code {
mut index := (segment.id_delta + char_code) & 0xffff mut index := (segment.id_delta + char_code) & 0xffff
if segment.id_range_offset > 0 { if segment.id_range_offset > 0 {
glyph_index_address := segment.id_range_offset + 2 * u32(char_code - segment.start_code) glyph_index_address := segment.id_range_offset +
2 * u32(char_code - segment.start_code)
tf.pos = glyph_index_address tf.pos = glyph_index_address
index = tf.get_u16() index = tf.get_u16()
} }
@ -909,12 +886,13 @@ fn (mut tm TrueTypeCmap) map_4(char_code int, mut tf TTF_File) int {
* *
******************************************************************************/ ******************************************************************************/
fn (mut tf TTF_File) read_hhea_table() { fn (mut tf TTF_File) read_hhea_table() {
dprintln("*** READ HHEA TABLE ***") dprintln('*** READ HHEA TABLE ***')
assert "hhea" in tf.tables assert 'hhea' in tf.tables
table_offset := tf.tables["hhea"].offset table_offset := tf.tables['hhea'].offset
tf.pos = table_offset tf.pos = table_offset
/*version :=*/ tf.get_fixed() // 0x00010000 // version :=
tf.get_fixed() // 0x00010000
tf.ascent = tf.get_fword() tf.ascent = tf.get_fword()
tf.descent = tf.get_fword() tf.descent = tf.get_fword()
@ -975,7 +953,7 @@ fn (mut tf TTF_File) create_kern_table0(vertical bool, cross bool) Kern0Table {
search_range := tf.get_u16() search_range := tf.get_u16()
entry_selector := tf.get_u16() entry_selector := tf.get_u16()
range_shift := tf.get_u16() range_shift := tf.get_u16()
dprintln("n_pairs: $n_pairs search_range: $search_range entry_selector: $entry_selector range_shift: $range_shift") dprintln('n_pairs: $n_pairs search_range: $search_range entry_selector: $entry_selector range_shift: $range_shift')
mut kt0 := Kern0Table{ mut kt0 := Kern0Table{
swap: (vertical && !cross) || (!vertical && cross) swap: (vertical && !cross) || (!vertical && cross)
@ -996,18 +974,18 @@ fn (mut tf TTF_File) create_kern_table0(vertical bool, cross bool) Kern0Table {
} }
fn (mut tf TTF_File) read_kern_table() { fn (mut tf TTF_File) read_kern_table() {
dprintln("*** READ KERN TABLE ***") dprintln('*** READ KERN TABLE ***')
if !("kern" in tf.tables){ if !('kern' in tf.tables) {
return return
} }
table_offset := tf.tables["kern"].offset table_offset := tf.tables['kern'].offset
tf.pos = table_offset tf.pos = table_offset
version := tf.get_u16() // must be 0 version := tf.get_u16() // must be 0
assert version == 0 // must be 0 assert version == 0 // must be 0
n_tables := tf.get_u16() n_tables := tf.get_u16()
dprintln("Kern Table version: $version Kern nTables: $n_tables") dprintln('Kern Table version: $version Kern nTables: $n_tables')
for _ in 0 .. n_tables { for _ in 0 .. n_tables {
st_version := tf.get_u16() // sub table version st_version := tf.get_u16() // sub table version
@ -1016,13 +994,13 @@ fn (mut tf TTF_File) read_kern_table() {
format := coverage >> 8 format := coverage >> 8
cross := coverage & 4 cross := coverage & 4
vertical := (coverage & 0x1) == 0 vertical := (coverage & 0x1) == 0
dprintln("Kerning subtable version [$st_version] format [$format] length [$length] coverage: [${coverage.hex()}]") dprintln('Kerning subtable version [$st_version] format [$format] length [$length] coverage: [$coverage.hex()]')
if format == 0 { if format == 0 {
dprintln("kern format: 0") dprintln('kern format: 0')
kern := tf.create_kern_table0(vertical, cross != 0) kern := tf.create_kern_table0(vertical, cross != 0)
tf.kern << kern tf.kern << kern
} else { } else {
dprintln("Unknown format -- skip") dprintln('Unknown format -- skip')
tf.pos = tf.pos + length tf.pos = tf.pos + length
} }
} }
@ -1045,29 +1023,27 @@ fn (mut tf TTF_File) next_kern(glyph_index int) (int, int){
return x, y return x, y
} }
/****************************************************************************** /******************************************************************************
* *
* TTF_File Utility * TTF_File Utility
* *
******************************************************************************/ ******************************************************************************/
pub pub fn (tf TTF_File) get_info_string() string {
fn (tf TTF_File) get_info_string() string{ txt := '----- Font Info -----
txt := "----- Font Info -----
font_family : $tf.font_family font_family : $tf.font_family
font_sub_family : $tf.font_sub_family font_sub_family : $tf.font_sub_family
full_name : $tf.full_name full_name : $tf.full_name
postscript_name : $tf.postscript_name postscript_name : $tf.postscript_name
version : $tf.version version : $tf.version
font_revision : $tf.font_revision font_revision : $tf.font_revision
magic_number : ${tf.magic_number.hex()} magic_number : $tf.magic_number.hex()
flags : ${tf.flags.hex()} flags : $tf.flags.hex()
created unixTS : ${tf.created} created unixTS : $tf.created
modified unixTS : ${tf.modified} modified unixTS : $tf.modified
box : [x_min:${tf.x_min}, y_min:${tf.y_min}, x_Max:${tf.x_max}, y_Max:${tf.y_max}] box : [x_min:$tf.x_min, y_min:$tf.y_min, x_Max:$tf.x_max, y_Max:$tf.y_max]
mac_style : ${tf.mac_style} mac_style : $tf.mac_style
----------------------- -----------------------
" '
return txt return txt
} }
@ -1080,17 +1056,27 @@ fn tst(){
mut tf := TTF_File{} mut tf := TTF_File{}
tf.buf = [ tf.buf = [
byte(0xFF), // 8 bit byte(0xFF), /* 8 bit */
0xF1, 0xF2, // 16 bit 0xF1,
0x81, 0x23, 0x45, 0x67, // 32 bit 0xF2, /* 16 bit */
0x12, 0x34, 0x12, 0x34, // get_2dot14 16 bit 0x81,
0x12, 0x34, 0x12, 0x34 // get_fixed 32 bit int 0x23,
0x45,
0x67, /* 32 bit */
0x12,
0x34,
0x12,
0x34, /* get_2dot14 16 bit */
0x12,
0x34,
0x12,
0x34 /* get_fixed 32 bit int */,
] ]
assert tf.get_u8().hex() == "ff" assert tf.get_u8().hex() == 'ff'
assert tf.get_u16().hex() == "f1f2" assert tf.get_u16().hex() == 'f1f2'
assert tf.get_u32().hex() == "81234567" assert tf.get_u32().hex() == '81234567'
dprintln("buf len: ${tf.buf.len}") dprintln('buf len: $tf.buf.len')
// dprintln( tf.get_u8().hex() ) // dprintln( tf.get_u8().hex() )
// dprintln( tf.get_u16().hex() ) // dprintln( tf.get_u16().hex() )
// dprintln( tf.get_u32().hex() ) // dprintln( tf.get_u32().hex() )

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -171,21 +171,27 @@ fn (mut ws Client) send_message_event(msg &Message) {
ws.debug_log('sending on_message event') ws.debug_log('sending on_message event')
for ev_handler in ws.message_callbacks { for ev_handler in ws.message_callbacks {
if !ev_handler.is_ref { if !ev_handler.is_ref {
ev_handler.handler(ws, msg) ev_handler.handler(ws, msg) or { ws.logger.error('send_message_event error: $err') }
} else { } else {
ev_handler.handler2(ws, msg, ev_handler.ref) ev_handler.handler2(ws, msg, ev_handler.ref) or {
ws.logger.error('send_message_event error: $err')
}
} }
} }
} }
// send_error_event invokes the on_error callback // send_error_event invokes the on_error callback
fn (mut ws Client) send_error_event(err string) { fn (mut ws Client) send_error_event(error string) {
ws.debug_log('sending on_error event') ws.debug_log('sending on_error event')
for ev_handler in ws.error_callbacks { for ev_handler in ws.error_callbacks {
if !ev_handler.is_ref { if !ev_handler.is_ref {
ev_handler.handler(mut ws, err) ev_handler.handler(mut ws, error) or {
ws.logger.error('send_error_event error: $error, err: $err')
}
} else { } else {
ev_handler.handler2(mut ws, err, ev_handler.ref) ev_handler.handler2(mut ws, error, ev_handler.ref) or {
ws.logger.error('send_error_event error: $error, err: $err')
}
} }
} }
} }
@ -195,9 +201,13 @@ fn (mut ws Client) send_close_event(code int, reason string) {
ws.debug_log('sending on_close event') ws.debug_log('sending on_close event')
for ev_handler in ws.close_callbacks { for ev_handler in ws.close_callbacks {
if !ev_handler.is_ref { if !ev_handler.is_ref {
ev_handler.handler(mut ws, code, reason) ev_handler.handler(mut ws, code, reason) or {
ws.logger.error('send_close_event error: $err')
}
} else { } else {
ev_handler.handler2(mut ws, code, reason, ev_handler.ref) ev_handler.handler2(mut ws, code, reason, ev_handler.ref) or {
ws.logger.error('send_close_event error: $err')
}
} }
} }
} }
@ -207,9 +217,11 @@ fn (mut ws Client) send_open_event() {
ws.debug_log('sending on_open event') ws.debug_log('sending on_open event')
for ev_handler in ws.open_callbacks { for ev_handler in ws.open_callbacks {
if !ev_handler.is_ref { if !ev_handler.is_ref {
ev_handler.handler(mut ws) ev_handler.handler(mut ws) or { ws.logger.error('send_open_event error: $err') }
} else { } else {
ev_handler.handler2(mut ws, ev_handler.ref) ev_handler.handler2(mut ws, ev_handler.ref) or {
ws.logger.error('send_open_event error: $err')
}
} }
} }
} }

View File

@ -39,7 +39,7 @@ const (
// validate_client validates client frame rules from RFC6455 // validate_client validates client frame rules from RFC6455
pub fn (mut ws Client) validate_frame(frame &Frame) ? { pub fn (mut ws Client) validate_frame(frame &Frame) ? {
if frame.rsv1 || frame.rsv2 || frame.rsv3 { if frame.rsv1 || frame.rsv2 || frame.rsv3 {
ws.close(1002, 'rsv cannot be other than 0, not negotiated') ws.close(1002, 'rsv cannot be other than 0, not negotiated') ?
return error('rsv cannot be other than 0, not negotiated') return error('rsv cannot be other than 0, not negotiated')
} }
if (int(frame.opcode) >= 3 && int(frame.opcode) <= 7) if (int(frame.opcode) >= 3 && int(frame.opcode) <= 7)
@ -113,7 +113,7 @@ fn (mut ws Client) validate_utf_8(opcode OPCode, payload []byte) ? {
if opcode in [.text_frame, .close] && !utf8.validate(payload.data, payload.len) { if opcode in [.text_frame, .close] && !utf8.validate(payload.data, payload.len) {
ws.logger.error('malformed utf8 payload, payload len: ($payload.len)') ws.logger.error('malformed utf8 payload, payload len: ($payload.len)')
ws.send_error_event('Recieved malformed utf8.') ws.send_error_event('Recieved malformed utf8.')
ws.close(1007, 'malformed utf8 payload') ws.close(1007, 'malformed utf8 payload') ?
return error('malformed utf8 payload') return error('malformed utf8 payload')
} }
} }

View File

@ -111,7 +111,7 @@ pub fn (mut ws Client) listen() ? {
defer { defer {
ws.logger.info('Quit client listener, server($ws.is_server)...') ws.logger.info('Quit client listener, server($ws.is_server)...')
if ws.state == .open { if ws.state == .open {
ws.close(1000, 'closed by client') ws.close(1000, 'closed by client') or { }
} }
} }
for ws.state == .open { for ws.state == .open {
@ -243,10 +243,6 @@ pub fn (mut ws Client) write_ptr(bytes byteptr, payload_len int, code OPCode) ?
mut header := []byte{len: header_len, init: `0`} // [`0`].repeat(header_len) mut header := []byte{len: header_len, init: `0`} // [`0`].repeat(header_len)
header[0] = byte(int(code)) | 0x80 header[0] = byte(int(code)) | 0x80
masking_key := create_masking_key() masking_key := create_masking_key()
defer {
unsafe {
}
}
if ws.is_server { if ws.is_server {
if payload_len <= 125 { if payload_len <= 125 {
header[1] = byte(payload_len) header[1] = byte(payload_len)
@ -315,7 +311,7 @@ pub fn (mut ws Client) write(bytes []byte, code OPCode) ? {
// write_str, writes a string with a websocket texttype to socket // write_str, writes a string with a websocket texttype to socket
pub fn (mut ws Client) write_str(str string) ? { pub fn (mut ws Client) write_str(str string) ? {
ws.write_ptr(str.str, str.len, .text_frame) ws.write_ptr(str.str, str.len, .text_frame) ?
} }
// close closes the websocket connection // close closes the websocket connection
@ -328,7 +324,7 @@ pub fn (mut ws Client) close(code int, message string) ? {
return ret_err return ret_err
} }
defer { defer {
ws.shutdown_socket() ws.shutdown_socket() or { }
ws.reset_state() ws.reset_state()
} }
ws.set_state(.closing) ws.set_state(.closing)

View File

@ -30,7 +30,7 @@ fn start_server() ? {
}) ? }) ?
s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? { s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? {
match msg.opcode { match msg.opcode {
.pong { ws.write_str('pong') } .pong { ws.write_str('pong') or { panic(err) } }
else { ws.write(msg.payload, msg.opcode) or { panic(err) } } else { ws.write(msg.payload, msg.opcode) or { panic(err) } }
} }
}) })