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())
mut out := os.create('table.html') ?
// Place the new row on top
table = '<tr>
table =
'<tr>
<td>$date.format()</td>
<td><a target=_blank href="https://github.com/vlang/v/commit/$commit">$commit</a></td>
<td>$message</td>
@ -80,15 +81,15 @@ fn main() {
<td>${diff4}ms</td>
</tr>\n' +
table.trim_space()
out.writeln(table)
out.writeln(table) ?
out.close()
// Regenerate index.html
header := os.read_file('header.html') ?
footer := os.read_file('footer.html') ?
mut res := os.create('index.html') ?
res.writeln(header)
res.writeln(table)
res.writeln(footer)
res.writeln(header) ?
res.writeln(table) ?
res.writeln(footer) ?
res.close()
}
exec('git checkout master')
@ -96,9 +97,7 @@ fn main() {
}
fn exec(s string) string {
e := os.exec(s) or {
panic(err)
}
e := os.exec(s) or { panic(err) }
return e.output.trim_right('\r\n')
}
@ -112,7 +111,7 @@ fn measure(cmd string, description string) int {
println(' Building...')
mut runs := []int{}
for r in 0 .. 5 {
println(' Sample ${r+1}/5')
println(' Sample ${r + 1}/5')
sw := time.new_stopwatch({})
exec(cmd)
runs << int(sw.elapsed().milliseconds())

View File

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

View File

@ -210,7 +210,7 @@ pub fn (mut ts TestSession) test() {
// cleanup generated .tmp.c files after successfull tests:
if ts.benchmark.nfail == 0 {
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)
if os.exists(generated_binary_fpath) {
if ts.rm_binaries {
os.rm(generated_binary_fpath)
os.rm(generated_binary_fpath) or { panic(err) }
}
}
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 ts.rm_binaries {
os.rm(generated_binary_fpath)
os.rm(generated_binary_fpath) or { panic(err) }
}
}
return sync.no_result
@ -422,7 +422,7 @@ pub fn header(msg string) {
pub fn setup_new_vtmp_folder() string {
now := time.sys_mono_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)
return new_vtmp_dir
}

View File

@ -28,26 +28,26 @@ fn get_vexe_path() string {
fn new_tdir() string {
tdir_ := os.join_path(os.temp_dir(), rand.ulid())
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)
return tdir_
}
fn cleanup_tdir() {
println('... removing tdir: $tdir')
os.rmdir_all(tdir)
os.rmdir_all(tdir) or { panic(err) }
}
fn main() {
println('> vroot: $vroot | vexe: $vexe | tdir: $tdir')
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" test $ok_fpath')
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" test $fail_fpath')
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, ')
line_len += b.len + 2
}
}
sb.write(']!\n')
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) {
fname := os.file_name(file)
fname_escpaed := fname.replace_each(['.', '_', '-', '_'])
byte_name := '$context.prefix$fname_escpaed'.to_lower()
fname_escaped := fname.replace_each(['.', '_', '-', '_'])
byte_name := '$context.prefix$fname_escaped'.to_lower()
fbytes := os.read_bytes(file) or { return error('Error: $err') }
return byte_name, fbytes
}
@ -131,12 +130,12 @@ fn main() {
}
max_bname := context.max_bname_len(file_byte_map.keys())
if context.write_file.len > 0 {
mut out_file := os.create(context.write_file) or { panic(err) }
out_file.write_str(context.header())
mut out_file := os.create(context.write_file) ?
out_file.write_str(context.header()) ?
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 {
print(context.header())
for bname, fbytes in file_byte_map {

View File

@ -55,9 +55,14 @@ fn main() {
//
tpath := os.join_path(session.vtmp_dir, texe)
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
}
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)
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()
}
@ -67,12 +67,12 @@ fn (c &Create) write_main(new bool) {
return
}
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)
exit(2)
}
main.write_str(main_content())
main.close()
mainfile.write_str(main_content()) or { panic(err) }
mainfile.close()
}
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
return
}
fl.write_str(gen_gitignore(c.name))
fl.write_str(gen_gitignore(c.name)) or { panic(err) }
fl.close()
}
}
@ -110,9 +110,7 @@ fn create() {
}
c.description = os.input('Input your project description: ')
println('Initialising ...')
os.mkdir(c.name) or {
panic(err)
}
os.mkdir(c.name) or { panic(err) }
c.write_vmod(true)
c.write_main(true)
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_data.writeln('];')
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) {
@ -162,7 +162,7 @@ fn (vd VDoc) get_resource(name string, out Output) string {
output_path := os.join_path(out.path, name)
if !os.exists(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
}

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)
output_path := os.join_path(pdoc.out.path, file_name)
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()
}
@ -358,7 +358,7 @@ fn (mut vd VDoc) generate_docs_from_file() {
os.mkdir(out.path) or { panic(err) }
} else {
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 {
favicon_path := os.join_path(favicons_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)
ulid := rand.ulid()
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 {
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 {
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_verify: $f.is_verify" }'
}

View File

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

View File

@ -109,21 +109,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
if !is_stdin_a_pipe {
println('')
}
os.rm(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])
}
cleanup_files([file, temp_file])
}
mut r := new_repl()
vexe := os.getenv('VEXE')
@ -198,7 +184,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
}
if r.line.starts_with('print') {
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 {
rerror(err)
return
@ -208,7 +194,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
mut temp_line := r.line
mut temp_flag := false
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 := [
'=',
@ -268,7 +254,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
}
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 {
rerror(err)
return
@ -355,3 +341,18 @@ fn (mut r Repl) get_one_line(prompt string) ?string {
rline := r.readline.read_line(prompt) or { return none }
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 tinyc {
#flag -lAdvapi32
#flag -lUser32
}
}
@ -19,20 +20,16 @@ fn main() {
fn setup_symlink(vexe string) {
link_dir := '/usr/local/bin'
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 ret := os.exec('ln -sf $vexe $link_path') or {
panic(err)
}
mut ret := os.exec('ln -sf $vexe $link_path') or { panic(err) }
if ret.exit_code == 0 {
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.')
link_path = '/data/data/com.termux/files/usr/bin/v'
ret = os.exec('ln -sf $vexe $link_path') or {
panic(err)
}
ret = os.exec('ln -sf $vexe $link_path') or { panic(err) }
if ret.exit_code == 0 {
println('Symlink "$link_path" has been created')
} else {
@ -52,9 +49,9 @@ fn setup_symlink_windows(vexe string) {
vsymlinkdir := os.join_path(vdir, '.bin')
mut vsymlink := os.join_path(vsymlinkdir, 'v.exe')
if !os.exists(vsymlinkdir) {
os.mkdir_all(vsymlinkdir) // will panic if fails
os.mkdir_all(vsymlinkdir) or { panic(err) } // will panic if fails
} else {
os.rm(vsymlink)
os.rm(vsymlink) or { panic(err) }
}
// First, try to create a native symlink at .\.bin\v.exe
os.symlink(vsymlink, vexe) or {
@ -64,9 +61,9 @@ fn setup_symlink_windows(vexe string) {
eprintln('Creating a batch file instead...')
vsymlink = os.join_path(vsymlinkdir, 'v.bat')
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.')
}
if !os.exists(vsymlink) {
@ -83,9 +80,7 @@ fn setup_symlink_windows(vexe string) {
// C.RegCloseKey(reg_sys_env_handle)
// }
// 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'))
mut new_paths := [vsymlinkdir]
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
fn send_setting_change_msg(message_data string) ?bool {
$if windows {
if C.SendMessageTimeout(os.hwnd_broadcast, os.wm_settingchange, 0, message_data.to_wide(), os.smto_abortifhung, 5000, 0) ==
0 {
if C.SendMessageTimeout(os.hwnd_broadcast, os.wm_settingchange, 0, message_data.to_wide(), os.smto_abortifhung, 5000, 0) == 0 {
return error('Could not broadcast WM_SETTINGCHANGE')
}
return true

View File

@ -108,9 +108,9 @@ fn (app App) show_current_v_version() {
fn (app App) backup(file string) {
backup_file := '${file}_old.exe'
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) {

View File

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

View File

@ -3,12 +3,14 @@ import io
fn main() {
// Make a new connection
mut conn := net.dial_tcp('google.com:80')?
defer { conn.close() }
mut conn := net.dial_tcp('google.com:80') ?
defer {
conn.close() or { }
}
// 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
result := io.read_all(reader: conn)?
result := io.read_all(reader: conn) ?
// Cast to string and print result
println(result.bytestr())
}

View File

@ -35,7 +35,7 @@ const (
f_0 = 0.0
)
/***************************** 3D Vector utility struct **********************/
//**************************** 3D Vector utility struct *********************
struct Vec {
mut:
x f64 = 0.0
@ -44,46 +44,42 @@ mut:
}
[inline]
fn (v Vec) + (b Vec) Vec{
return Vec{ v.x + b.x , v.y + b.y, v.z + b.z }
fn (v Vec) + (b Vec) Vec {
return Vec{v.x + b.x, v.y + b.y, v.z + b.z}
}
[inline]
fn (v Vec) - (b Vec) Vec{
return Vec{ v.x - b.x , v.y - b.y, v.z - b.z }
fn (v Vec) - (b Vec) Vec {
return Vec{v.x - b.x, v.y - b.y, v.z - b.z}
}
[inline]
fn (v Vec) * (b Vec) Vec{
return Vec{ v.x * b.x , v.y * b.y, v.z * b.z }
fn (v Vec) * (b Vec) Vec {
return Vec{v.x * b.x, v.y * b.y, v.z * b.z}
}
[inline]
fn (v Vec) dot (b Vec) f64{
fn (v Vec) dot(b Vec) f64 {
return v.x * b.x + v.y * b.y + v.z * b.z
}
[inline]
fn (v Vec) mult_s (b f64) Vec{
return Vec{ v.x * b , v.y * b, v.z * b }
fn (v Vec) mult_s(b f64) Vec {
return Vec{v.x * b, v.y * b, v.z * b}
}
[inline]
fn (v Vec) cross (b Vec) 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
}
fn (v Vec) cross(b Vec) 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}
}
[inline]
fn (v Vec) norm () Vec {
fn (v Vec) norm() Vec {
tmp_norm := 1.0 / math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
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 {
width int
height int
@ -93,9 +89,9 @@ struct Image {
fn new_image(w int, h int) Image {
vecsize := int(sizeof(Vec))
return Image{
width: w,
height: h,
data: &Vec(vcalloc(vecsize*w*h))
width: w
height: 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) {
npixels := image.width * image.height
mut f_out := os.create(file_name) or { panic(err) }
f_out.writeln('P3')
f_out.writeln('${image.width} ${image.height}')
f_out.writeln('255')
for i in 0..npixels {
c_r := to_int(unsafe{image.data[i]}.x)
c_g := to_int(unsafe{image.data[i]}.y)
c_b := to_int(unsafe{image.data[i]}.z)
f_out.write_str('$c_r $c_g $c_b ')
f_out.writeln('P3') or { panic(err) }
f_out.writeln('$image.width $image.height') or { panic(err) }
f_out.writeln('255') or { panic(err) }
for i in 0 .. npixels {
c_r := to_int(unsafe { image.data[i] }.x)
c_g := to_int(unsafe { image.data[i] }.y)
c_b := to_int(unsafe { image.data[i] }.z)
f_out.write_str('$c_r $c_g $c_b ') or { panic(err) }
}
f_out.close()
}
/*********************************** Ray *************************************/
//********************************** Ray ************************************
struct Ray {
o Vec
d Vec
@ -128,7 +124,7 @@ enum Refl_t {
refr
}
/********************************* Sphere ************************************/
//******************************** Sphere ***********************************
struct Sphere {
rad f64 = 0.0 // radius
p Vec // position
@ -137,7 +133,7 @@ struct Sphere {
refl Refl_t // reflection type => [diffuse, specular, refractive]
}
fn (sp Sphere) intersect (r Ray) f64 {
fn (sp Sphere) intersect(r Ray) f64 {
op := sp.p - r.o // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0
b := op.dot(r.d)
mut det := b * b - op.dot(op) + sp.rad * sp.rad
@ -167,80 +163,179 @@ fn (sp Sphere) intersect (r Ray) f64 {
* The sphere fileds are: Sphere{radius, position, emission, color, material}
******************************************************************************/
const (
cen = Vec{50, 40.8, -860} // used by scene 1
spheres = [
[// scene 0 cornnel box
Sphere{rad: 1e+5, p: Vec{ 1e+5 +1,40.8,81.6} , e: Vec{} , c: Vec{.75,.25,.25} , refl: .diff},//Left
Sphere{rad: 1e+5, p: Vec{-1e+5 +99,40.8,81.6}, e: Vec{} , c: Vec{.25,.25,.75} , refl: .diff},//Rght
Sphere{rad: 1e+5, p: Vec{50,40.8, 1e+5} , e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Back
Sphere{rad: 1e+5, p: Vec{50,40.8,-1e+5 +170} , e: Vec{} , c: Vec{} , refl: .diff},//Frnt
Sphere{rad: 1e+5, p: Vec{50, 1e+5, 81.6} , e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//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
cen = Vec{50, 40.8, -860} // used by scene 1
spheres = [
[/* scene 0 cornnel box */ Sphere{
rad: 1e+5
p: Vec{1e+5 + 1, 40.8, 81.6}
e: Vec{}
c: Vec{.75, .25, .25}
refl: .diff
}, /* Left */ Sphere{
rad: 1e+5
p: Vec{-1e+5 + 99, 40.8, 81.6}
e: Vec{}
c: Vec{.25, .25, .75}
refl: .diff
}, /* Rght */ Sphere{
rad: 1e+5
p: Vec{50, 40.8, 1e+5}
e: Vec{}
c: Vec{.75, .75, .75}
refl: .diff
}, /* Back */ Sphere{
rad: 1e+5
p: Vec{50, 40.8, -1e+5 + 170}
e: Vec{}
c: Vec{}
refl: .diff
}, /* Frnt */ Sphere{
rad: 1e+5
p: Vec{50, 1e+5, 81.6}
e: Vec{}
c: Vec{.75, .75, .75}
refl: .diff
}, /* 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
)
/*********************************** Utilities *******************************/
//********************************** Utilities ******************************
[inline]
fn clamp(x f64) f64 {
if x < 0 { return 0 }
if x > 1 { return 1 }
if x < 0 {
return 0
}
if x > 1 {
return 1
}
return x
}
[inline]
fn to_int(x f64) int {
p := math.pow(clamp(x), 1.0/2.2)
return int(p*255.0+0.5)
p := math.pow(clamp(x), 1.0 / 2.2)
return int(p * 255.0 + 0.5)
}
fn intersect(r Ray, spheres &Sphere, nspheres int) (bool, f64, int){
fn intersect(r Ray, spheres &Sphere, nspheres int) (bool, f64, int) {
mut d := 0.0
mut t := inf
mut id := 0
for i:=nspheres-1; i >= 0; i-- {
d = unsafe{spheres[i]}.intersect(r)
for i := nspheres - 1; i >= 0; i-- {
d = unsafe { spheres[i] }.intersect(r)
if d > 0 && d < t {
t = d
id = i
}
}
return (t < inf) , t, id
return (t < inf), t, id
}
// some casual random function, try to avoid the 0
fn rand_f64() f64 {
x := rand.u32() & 0x3FFF_FFFF
return f64(x)/f64(0x3FFF_FFFF)
return f64(x) / f64(0x3FFF_FFFF)
}
const(
const (
cache_len = 65536 // the 2*pi angle will be splitted in 65536 part
cache_mask = cache_len - 1 // mask to speed-up the module process
)
@ -254,7 +349,7 @@ mut:
fn new_tabs() Cache {
mut c := Cache{}
inv_len := 1.0 / f64(cache_len)
for i in 0..cache_len {
for i in 0 .. cache_len {
x := f64(i) * math.pi * 2.0 * inv_len
c.sin_tab[i] = math.sin(x)
c.cos_tab[i] = math.cos(x)
@ -262,12 +357,12 @@ fn new_tabs() Cache {
return c
}
/************* Cache for sin/cos speed-up table and scene selector ***********/
//************ Cache for sin/cos speed-up table and scene selector **********
const (
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 {
if depthi > 1024 {
eprintln('depthi: $depthi')
@ -279,12 +374,15 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
mut res := false // result of intersect
v_1 := 1.0
//v_2 := f64(2.0)
// v_2 := f64(2.0)
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)
if !res { return Vec{} } //if miss, return black
if !res {
return Vec{}
}
// if miss, return black
obj := scene[id] // the hit object
@ -308,15 +406,15 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
depth++
if depth > 5 {
if rand_f64() < p {
f = f.mult_s(f64(1.0)/p)
f = f.mult_s(f64(1.0) / p)
} else {
return obj.e //R.R.
return obj.e // R.R.
}
}
if obj.refl == .diff { // Ideal DIFFUSE reflection
// **Full Precision**
//r1 := f64(2.0 * math.pi) * rand_f64()
// r1 := f64(2.0 * math.pi) * rand_f64()
// tabbed speed-up
r1 := rand.u32() & cache_mask
@ -326,25 +424,22 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
w := nl
mut u := if math.abs(w.x) > f64(0.1) {
Vec{0, 1, 0}
} else {
Vec{1, 0, 0}
}
mut u := if math.abs(w.x) > f64(0.1) { Vec{0, 1, 0} } else { Vec{1, 0, 0} }
u = u.cross(w).norm()
v := w.cross(u)
// **Full Precision**
//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
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)
} else {
if obj.refl == .spec { // Ideal SPECULAR reflection
return obj.e + f * radiance(Ray{x, r.d - n.mult_s(2.0 * n.dot(r.d)) }, depth, scene_id)
return obj.e + f * radiance(Ray{x, r.d - n.mult_s(2.0 * n.dot(r.d))}, depth, scene_id)
}
}
@ -379,18 +474,16 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
mut tmp := Vec{}
if depth > 2 {
// Russian roulette
tmp = if rand_f64() < pp {
radiance(refl_ray, depth, scene_id).mult_s(rp)
tmp = if rand_f64() < pp { radiance(refl_ray, depth, scene_id).mult_s(rp) } else { radiance(Ray{x, tdir},
depth, scene_id).mult_s(tp) }
} else {
radiance(Ray{x, tdir}, depth, scene_id).mult_s(tp)
}
} else {
tmp = (radiance(refl_ray, depth, scene_id).mult_s(re)) + (radiance( Ray{x, tdir}, depth, scene_id).mult_s(tr))
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)
}
/************************ beam scan routine **********************************/
//*********************** beam scan routine *********************************
fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image {
image := new_image(w, h)
@ -400,7 +493,7 @@ fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image {
samps1 := f64(1.0 / f64(samps))
cam := Ray{Vec{50, 52, 295.6}, Vec{0, -0.042612, -1}.norm()} // cam position, direction
cx := Vec{ f64(w) * 0.5135 / f64(h), 0, 0}
cx := Vec{f64(w) * 0.5135 / f64(h), 0, 0}
cy := cx.cross(cam.d).norm().mult_s(0.5135)
mut r := Vec{}
@ -409,28 +502,28 @@ fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image {
v_2 := f64(2.0)
// OpenMP injection point! #pragma omp parallel for schedule(dynamic, 1) shared(c)
for y:=0; y < h; y++ {
eprint("\rRendering (${samps * 4} spp) ${(100.0 * f64(y)) / (f64(h) - 1.0):5.2f}%")
for x in 0..w {
for y := 0; y < h; y++ {
eprint('\rRendering (${samps * 4} spp) ${(100.0 * f64(y)) / (f64(h) - 1.0):5.2f}%')
for x in 0 .. w {
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
for sy := 0; sy < 2; sy ++ {
for sx := 0; sx < 2; sx ++ {
r = Vec{0,0,0}
for _ in 0..samps {
for sy := 0; sy < 2; sy++ {
for sx := 0; sx < 2; sx++ {
r = Vec{0, 0, 0}
for _ in 0 .. samps {
r1 := v_2 * rand_f64()
dx := if r1 < v_1 { math.sqrt(r1) - v_1 } else { v_1 - math.sqrt(v_2 - r1) }
r2 := v_2 * rand_f64()
dy := if r2 < v_1 { math.sqrt(r2) - v_1 } else { v_1 - math.sqrt(v_2 - r2) }
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
r = r + radiance(Ray{cam.o+d.mult_s(140.0), d.norm()}, 0, scene_id).mult_s(samps1)
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
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
}
}
@ -465,20 +558,18 @@ fn main() {
if os.args.len == 6 {
height = os.args[5].int()
}
// change the seed for a different result
rand.seed([u32(2020), 0])
t1:=time.ticks()
t1 := time.ticks()
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)
t3 := time.ticks()
image.save_as_ppm( file_name )
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 (
colors = [
tui.Color{33, 150, 243}
tui.Color{0, 150, 136}
tui.Color{205, 220, 57}
tui.Color{255, 152, 0}
tui.Color{244, 67, 54}
tui.Color{156, 39, 176}
tui.Color{33, 150, 243},
tui.Color{0, 150, 136},
tui.Color{205, 220, 57},
tui.Color{255, 152, 0},
tui.Color{244, 67, 54},
tui.Color{156, 39, 176},
]
)
@ -66,27 +66,33 @@ fn event(e &tui.Event, x voidptr) {
}
.space, .enter {
app.color_idx++
if app.color_idx == colors.len { app.color_idx = 0 }
app.color = colors[app.color_idx]
} else {}
if app.color_idx == colors.len {
app.color_idx = 0
}
} .mouse_move, .mouse_drag, .mouse_down {
app.points << Point{ e.x, e.y }
} .mouse_scroll {
app.color = colors[app.color_idx]
}
else {}
}
}
.mouse_move, .mouse_drag, .mouse_down {
app.points << Point{e.x, e.y}
}
.mouse_scroll {
d := if e.direction == .up { 0.1 } else { -0.1 }
app.cut_rate += d
if app.cut_rate < 1 { app.cut_rate = 1 }
} else {}
if app.cut_rate < 1 {
app.cut_rate = 1
}
}
else {}
}
}
mut app := &App{}
app.tui = tui.init(
user_data: app,
frame_fn: frame,
event_fn: event,
user_data: app
frame_fn: frame
event_fn: event
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.write('V term.input event viewer (press `esc` to exit)\n\n')
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 {
app.tui.write('\nModifiers: $e.modifiers = ')
if e.modifiers & tui.ctrl != 0 { app.tui.write('ctrl. ') }
if e.modifiers & tui.shift != 0 { app.tui.write('shift ') }
if e.modifiers & tui.alt != 0 { app.tui.write('alt. ') }
if e.modifiers & tui.ctrl != 0 {
app.tui.write('ctrl. ')
}
if e.modifiers & tui.shift != 0 {
app.tui.write('shift ')
}
if e.modifiers & tui.alt != 0 {
app.tui.write('alt. ')
}
}
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{}
app.tui = tui.init(
user_data: app,
user_data: app
event_fn: event
window_title: 'V term.ui event viewer'
hide_cursor: true
capture_events: true
frame_rate: 60
use_alternate_buffer: false
)
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.height = h
term.erase_del_clear()
term.set_cursor_position({
term.set_cursor_position(
x: 0
y: 0
})
)
}
fn (mut a App) start_game() {
@ -66,10 +66,10 @@ fn (mut a App) quit() {
a.game.quit()
return
}
term.set_cursor_position({
term.set_cursor_position(
x: 0
y: 0
})
)
exit(0)
}
@ -482,7 +482,7 @@ fn event(e &ui.Event, x voidptr) {
// main
mut app := &App{}
app.tui = ui.init({
app.tui = ui.init(
user_data: app
init_fn: init
frame_fn: frame
@ -492,5 +492,5 @@ app.tui = ui.init({
capture_events: true
hide_cursor: true
frame_rate: 60
})
app.tui.run()
)
app.tui.run() ?

View File

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

View File

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

View File

@ -44,7 +44,7 @@ fn (mut a App) set_status(msg string, duration_ms int) {
fn (mut a App) save() {
if a.cfile().len > 0 {
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)
} else {
a.set_status('No file loaded', 4000)
@ -79,7 +79,6 @@ fn (mut a App) visit_next_file() {
a.init_file()
}
fn (mut a App) footer() {
w, h := a.tui.window_width, a.tui.window_height
mut b := a.ed
@ -99,16 +98,16 @@ fn (mut a App) footer() {
if a.t <= 0 {
status = ''
} else {
a.tui.set_bg_color({
a.tui.set_bg_color(
r: 200
g: 200
b: 200
})
a.tui.set_color({
)
a.tui.set_color(
r: 0
g: 0
b: 0
})
)
a.tui.draw_text((w + 4 - status.len) / 2, h - 1, ' $status ')
a.tui.reset()
a.t -= 33
@ -303,7 +302,7 @@ fn (mut b Buffer) free() {
for line in b.lines {
line.free()
}
unsafe {b.lines.free()}
unsafe { b.lines.free() }
}
fn (mut b Buffer) move_updown(amount int) {
@ -334,7 +333,7 @@ fn (mut b Buffer) move_cursor(amount int, movement Movement) {
b.move_updown(-dlines)
}
.page_down {
dlines := imin(b.lines.len-1, b.cursor.pos_y + amount) - b.cursor.pos_y
dlines := imin(b.lines.len - 1, b.cursor.pos_y + amount) - b.cursor.pos_y
b.move_updown(dlines)
}
.left {
@ -374,13 +373,19 @@ fn (mut b Buffer) move_to_word(movement Movement) {
x = 0
}
// 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
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 x + a >= 0 && x + a <= line.len {
x += a
} else if a < 0 && y+1 > b.lines.len && y-1 >= 0 {
} else if a < 0 && y + 1 > b.lines.len && y - 1 >= 0 {
y += a
x = 0
}
@ -388,11 +393,19 @@ fn (mut b Buffer) move_to_word(movement Movement) {
}
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 {
return if x < y { x } else { y }
return if x < y {
x
} else {
y
}
}
struct Cursor {
@ -443,9 +456,7 @@ fn (mut a App) init_file() {
// 'vico: ' +
a.tui.set_window_title(a.files[a.current_file])
mut b := a.ed
content := os.read_file(a.files[a.current_file]) or {
panic(err)
}
content := os.read_file(a.files[a.current_file]) or { panic(err) }
b.put(content)
a.ed.cursor.pos_x = init_x
a.ed.cursor.pos_y = init_y
@ -573,12 +584,12 @@ fn main() {
mut a := &App{
files: files
}
a.tui = tui.init({
a.tui = tui.init(
user_data: a
init_fn: init
frame_fn: frame
event_fn: event
capture_events: true
})
a.tui.run()
)
a.tui.run() ?
}

View File

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

View File

@ -16,18 +16,16 @@ fn main() {
if line == '' {
break
}
ws.write_str(line)
}
ws.close(1000, 'normal') or {
println(term.red('panicing $err'))
ws.write_str(line) ?
}
ws.close(1000, 'normal') or { println(term.red('panicing $err')) }
unsafe {
ws.free()
}
}
fn start_client() ?&websocket.Client {
mut ws := websocket.new_client('ws://localhost:30000')?
mut ws := websocket.new_client('ws://localhost:30000') ?
// mut ws := websocket.new_client('wss://echo.websocket.org:443')?
// use on_open_ref if you want to send any reference object
ws.on_open(fn (mut ws websocket.Client) ? {
@ -49,12 +47,8 @@ fn start_client() ?&websocket.Client {
}
})
ws.connect() or {
println(term.red('error on connect: $err'))
}
ws.connect() or { println(term.red('error on connect: $err')) }
go ws.listen() or {
println(term.red('error on listen $err'))
}
go ws.listen() or { println(term.red('error on listen $err')) }
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
if version_flag {
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)
}
}
@ -280,7 +280,7 @@ fn (cmd Command) check_required_flags() {
pub fn (cmd Command) execute_help() {
if cmd.commands.contains('help') {
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 {
print(cmd.help_message())
}

View File

@ -22,7 +22,7 @@ fn test_vexe() {
fn test_can_compile_library() {
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')
eprintln('res: $res')
assert os.is_file(library_file_name)
@ -34,7 +34,7 @@ fn test_can_compile_main_program() {
result := v_compile('run use.v')
eprintln('result: $result')
assert result.output.contains('res: 4')
os.rm(library_file_name)
os.rm(library_file_name) or { }
}
fn v_compile(vopts string) os.Result {

View File

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

View File

@ -106,7 +106,7 @@ pub fn (mut l Log) close() {
fn (mut l Log) log_file(s string, level Level) {
timestamp := time.now().format_ss()
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.

View File

@ -36,7 +36,7 @@ pub fn socket_error(potential_code int) ?int {
pub fn wrap_error(error_code int) ? {
$if windows {
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 {
if error_code == 0 {

View File

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

View File

@ -1,42 +1,49 @@
import net.ftp
// NB: this function makes network calls to external servers,
// 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`
fn ftp_client_test_inside() ? {
$if !network ? { return }
mut ftp := ftp.new()
defer {
ftp.close()
fn test_ftp_cleint() {
$if !network ? {
return
}
connect_result := ftp.connect('ftp.redhat.com')?
// NB: this function makes network calls to external servers,
// 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`
ftp_client_test_inside() or { panic(err) }
}
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
login_result := ftp.login('ftp', 'ftp')?
login_result := zftp.login('ftp', 'ftp') ?
assert login_result
pwd := ftp.pwd()?
pwd := zftp.pwd() ?
assert pwd.len > 0
ftp.cd('/')
dir_list1 := ftp.dir() or {
zftp.cd('/') or {
assert false
return
}
dir_list1 := zftp.dir() or {
assert false
return
}
assert dir_list1.len > 0
ftp.cd('/suse/linux/enterprise/11Server/en/SAT-TOOLS/SRPMS/')
dir_list2 := ftp.dir() or {
zftp.cd('/suse/linux/enterprise/11Server/en/SAT-TOOLS/SRPMS/') or {
assert false
return
}
dir_list2 := zftp.dir() or {
assert false
return
}
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
return
}
assert blob.len > 0
}
fn test_ftp_cleint() {
ftp_client_test_inside() or {
panic(err)
}
}

View File

@ -5,13 +5,11 @@ module http
import os
pub fn download_file(url string, out string)? {
$if debug_http? {
pub fn download_file(url string, out string) ? {
$if debug_http ? {
println('download file url=$url out=$out')
}
s := get(url) or {
return error(err)
}
os.write_file(out, s.text)
s := get(url) or { return error(err) }
os.write_file(out, s.text) ?
// 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 {
return fetch_with_method(.post, url, data: data, headers: {
'Content-Type': content_type_default
})
return fetch_with_method(.post, url,
data: data
headers: {
'Content-Type': http.content_type_default
}
)
}
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'
})
}
)
}
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'
}, data: url_encode_form_data(data))
}
data: url_encode_form_data(data)
)
}
pub fn put(url string, data string) ?Response {
return fetch_with_method(.put, url, data: data, headers: {
'Content-Type': content_type_default
})
return fetch_with_method(.put, url,
data: data
headers: {
'Content-Type': http.content_type_default
}
)
}
pub fn patch(url string, data string) ?Response {
return fetch_with_method(.patch, url, data: data, headers: {
'Content-Type': content_type_default
})
return fetch_with_method(.patch, url,
data: data
headers: {
'Content-Type': http.content_type_default
}
)
}
pub fn head(url string) ?Response {
@ -165,11 +180,11 @@ fn build_url_from_fetch(_url string, config FetchConfig) ?string {
}
fn (mut req Request) free() {
unsafe {req.headers.free()}
unsafe { req.headers.free() }
}
fn (mut resp Response) free() {
unsafe {resp.headers.free()}
unsafe { resp.headers.free() }
}
// add_header adds the key and value of an HTTP request header
@ -199,8 +214,8 @@ pub fn (req &Request) do() ?Response {
mut resp := Response{}
mut no_redirects := 0
for {
if no_redirects == max_redirects {
return error('http.request.do: maximum number of redirects reached ($max_redirects)')
if no_redirects == http.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) ?
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
client.write(s.bytes()) ?
mut bytes := io.read_all(reader: client) ?
client.close()
client.close() ?
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
pub fn (mut c Client) quit() ? {
c.send_str('QUIT\r\n')
c.expect_reply(.close)
c.send_str('QUIT\r\n') ?
c.expect_reply(.close) ?
c.conn.close() ?
c.is_open = false
}
@ -166,7 +166,7 @@ fn (mut c Client) send_mailto(to string) ? {
fn (mut c Client) send_data() ? {
c.send_str('DATA\r\n') ?
c.expect_reply(.mail_start)
c.expect_reply(.mail_start) ?
}
fn (mut c Client) send_body(cfg Mail) ? {

View File

@ -22,8 +22,8 @@ pub fn dial_tcp(address string) ?&TcpConn {
s.connect(address) ?
return &TcpConn{
sock: s
read_timeout: tcp_default_read_timeout
write_timeout: tcp_default_write_timeout
read_timeout: net.tcp_default_read_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
pub fn (mut c TcpConn) write_ptr(b byteptr, len int) ? {
$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 {
@ -48,7 +49,7 @@ pub fn (mut c TcpConn) write_ptr(b byteptr, len int) ? {
if sent < 0 {
code := error_code()
if code == int(error_ewouldblock) {
c.wait_for_write()
c.wait_for_write() ?
continue
} else {
wrap_error(code) ?
@ -164,9 +165,9 @@ pub fn (c &TcpConn) peer_ip() ?string {
return res
}
pub fn (c &TcpConn) str() string {
// TODO
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}'
pub fn (c TcpConn) str() string {
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: $s }'
}
pub struct TcpListener {
@ -213,8 +214,8 @@ pub fn (mut l TcpListener) accept() ?&TcpConn {
new_sock := tcp_socket_from_handle(new_handle) ?
return &TcpConn{
sock: new_sock
read_timeout: tcp_default_read_timeout
write_timeout: tcp_default_write_timeout
read_timeout: net.tcp_default_read_timeout
write_timeout: net.tcp_default_write_timeout
}
}
@ -266,7 +267,7 @@ fn new_tcp_socket() ?TcpSocket {
t := true
socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ?
} $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
}
@ -281,7 +282,7 @@ fn tcp_socket_from_handle(sockfd int) ?TcpSocket {
t := true
socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ?
} $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
}
@ -322,12 +323,12 @@ fn (mut s TcpSocket) connect(a string) ? {
return none
}
_ := error_code()
write_result := s.@select(.write, connect_timeout) ?
write_result := s.@select(.write, net.connect_timeout) ?
if write_result {
// succeeded
return none
}
except_result := s.@select(.except, connect_timeout) ?
except_result := s.@select(.except, net.connect_timeout) ?
if except_result {
return err_connect_failed
}

View File

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

View File

@ -33,8 +33,8 @@ pub fn dial_udp(laddr string, raddr string) ?&UdpConn {
}
return &UdpConn{
sock: sock
read_timeout: udp_default_read_timeout
write_timeout: udp_default_write_timeout
read_timeout: net.udp_default_read_timeout
write_timeout: net.udp_default_write_timeout
}
}
@ -162,8 +162,8 @@ pub fn listen_udp(port int) ?&UdpConn {
s := new_udp_socket(port) ?
return &UdpConn{
sock: s
read_timeout: udp_default_read_timeout
write_timeout: udp_default_write_timeout
read_timeout: net.udp_default_read_timeout
write_timeout: net.udp_default_write_timeout
}
}
@ -183,7 +183,7 @@ fn new_udp_socket(local_port int) ?&UdpSocket {
t := true
socket_error(C.ioctlsocket(sockfd, fionbio, &t)) ?
} $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
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
// escape them (because hosts can`t use %-encoding for
// ASCII bytes).
if c in
[`!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `:`, `[`, `]`, `<`, `>`, `"`] {
if
c in [`!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `:`, `[`, `]`, `<`, `>`, `"`] {
return false
}
}
@ -162,7 +162,7 @@ fn unescape(s_ string, mode EncodingMode) ?string {
if s.len > 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
// 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
// in IPv6 scoped-address literals. Yay.
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 {
// 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.
v := ((unhex(s[i + 1]) << byte(4)) | unhex(s[i + 2]))
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
@ -193,9 +193,8 @@ fn unescape(s_ string, mode EncodingMode) ?string {
i++
}
else {
if (mode == .encode_host ||
mode == .encode_zone) &&
s[i] < 0x80 && should_escape(s[i], mode) {
if (mode == .encode_host || mode == .encode_zone) && s[i] < 0x80
&& should_escape(s[i], mode) {
error(error_msg('unescape: invalid character in host name', s[i..i + 1]))
}
i++
@ -429,11 +428,12 @@ fn split(s string, sep byte, cutc bool) (string, string) {
pub fn parse(rawurl string) ?URL {
// Cut off #frag
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 == '' {
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
return url
}
@ -570,7 +570,7 @@ fn parse_host(host string) ?string {
// parse an IP-Literal in RFC 3986 and RFC 6874.
// E.g., '[fe80::1]', '[fe80::1%25en0]', '[fe80::1]:80'.
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..]
if !valid_optional_port(colon_port) {
@ -785,7 +785,7 @@ pub fn parse_query(query string) ?Values {
// but any errors will be silent
fn parse_query_silent(query string) Values {
mut m := new_values()
parse_query_values(mut m, query)
parse_query_values(mut m, query) or { }
return m
}
@ -1029,7 +1029,8 @@ pub fn valid_userinfo(s string) bool {
continue
}
match r {
`-`, `.`, `_`, `:`, `~`, `!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `%`, `@` {
`-`, `.`, `_`, `:`, `~`, `!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `%`,
`@` {
continue
}
else {

View File

@ -9,16 +9,16 @@ const (
fn testsuite_begin() {
eprintln('testsuite_begin, tfolder = $tfolder')
os.rmdir_all(tfolder)
os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder)
os.mkdir_all(tfolder)
os.mkdir_all(tfolder) or { panic(err) }
os.chdir(tfolder)
assert os.is_dir(tfolder)
}
fn testsuite_end() {
os.chdir(os.wd_at_startup)
os.rmdir_all(tfolder)
os.rmdir_all(tfolder) or { panic(err) }
assert !os.is_dir(tfolder)
}
@ -27,7 +27,7 @@ fn test_inode_file_type() {
mut file := os.open_file(filename, 'w', 0o600) or { return }
file.close()
mode := os.inode(filename)
os.rm(filename)
os.rm(filename) or { panic(err) }
assert mode.typ == .regular
}
@ -36,7 +36,7 @@ fn test_inode_file_owner_permission() {
mut file := os.open_file(filename, 'w', 0o600) or { return }
file.close()
mode := os.inode(filename)
os.rm(filename)
os.rm(filename) or { }
assert mode.owner.read
assert mode.owner.write
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 overwrite {
rm(adjusted_path)
rm(adjusted_path) ?
} else {
return error('Destination file path already exist')
}
@ -65,7 +65,7 @@ pub fn cp_all(src string, dst string, overwrite bool) ? {
mkdir(dp) ?
}
cp_all(sp, dp, overwrite) or {
rmdir(dp)
rmdir(dp) or { return error(err) }
return error(err)
}
}
@ -144,7 +144,7 @@ pub fn file_exists(_path string) bool {
[deprecated]
pub fn rmdir_recursive(path string) {
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.
@ -154,7 +154,7 @@ pub fn rmdir_all(path string) ? {
for item in items {
fullpath := join_path(path, item)
if is_dir(fullpath) {
rmdir_all(fullpath)
rmdir_all(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`.
pub fn write_file(path string, text string) ? {
mut f := create(path) ?
f.write(text.bytes())
f.write(text.bytes()) ?
f.close()
}

View File

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

View File

@ -13,9 +13,9 @@ const args_at_start = os.args.clone()
fn testsuite_begin() {
eprintln('testsuite_begin, tfolder = $tfolder')
os.rmdir_all(tfolder)
os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder)
os.mkdir_all(tfolder)
os.mkdir_all(tfolder) or { panic(err) }
os.chdir(tfolder)
assert os.is_dir(tfolder)
// println('args_at_start: $args_at_start')
@ -25,7 +25,7 @@ fn testsuite_begin() {
fn testsuite_end() {
os.chdir(os.wd_at_startup)
os.rmdir_all(tfolder)
os.rmdir_all(tfolder) or { }
assert !os.is_dir(tfolder)
// eprintln('testsuite_end , tfolder = $tfolder removed.')
}
@ -38,12 +38,12 @@ fn test_open_file() {
os.File{}
}
mut file := os.open_file(filename, 'w+', 0o666) or { panic(err) }
file.write_str(hello)
file.write_str(hello) or { panic(err) }
file.close()
assert hello.len == os.file_size(filename)
read_hello := os.read_file(filename) or { panic('error reading file $filename') }
assert hello == read_hello
os.rm(filename)
os.rm(filename) or { panic(err) }
}
fn test_open_file_binary() {
@ -60,7 +60,7 @@ fn test_open_file_binary() {
assert hello.len == os.file_size(filename)
read_hello := os.read_bytes(filename) or { panic('error reading file $filename') }
assert bytes == read_hello
os.rm(filename)
os.rm(filename) or { panic(err) }
}
// fn test_file_get_line() {
@ -87,23 +87,23 @@ fn test_create_file() {
filename := './test1.txt'
hello := 'hello world!'
mut f := os.create(filename) or { panic(err) }
f.write_str(hello)
f.write_str(hello) or { panic(err) }
f.close()
assert hello.len == os.file_size(filename)
os.rm(filename)
os.rm(filename) or { panic(err) }
}
fn test_is_file() {
// Setup
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')
// Test things that shouldn't be a file
assert os.is_file(work_dir) == false
assert os.is_file('non-existent_file.tmp') == false
// Test 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)
// Test dir symlinks
$if windows {
@ -126,11 +126,11 @@ fn test_is_file() {
fn test_write_and_read_string_to_file() {
filename := './test1.txt'
hello := 'hello world!'
os.write_file(filename, hello)
os.write_file(filename, hello) or { panic(err) }
assert hello.len == os.file_size(filename)
read_hello := os.read_file(filename) or { panic('error reading file $filename') }
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
@ -166,7 +166,7 @@ fn test_write_and_read_bytes() {
assert nread == 0
file_read.close()
// We finally delete the test file.
os.rm(file_name)
os.rm(file_name) or { panic(err) }
}
fn test_create_and_delete_folder() {
@ -175,7 +175,7 @@ fn test_create_and_delete_folder() {
assert os.is_dir(folder)
folder_contents := os.ls(folder) or { panic(err) }
assert folder_contents.len == 0
os.rmdir(folder)
os.rmdir(folder) or { panic(err) }
folder_exists := os.is_dir(folder)
assert folder_exists == false
}
@ -191,61 +191,61 @@ fn test_walk() {
folder := 'test_walk'
os.mkdir(folder) or { panic(err) }
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.rm(file1)
os.rmdir(folder)
os.rm(file1) or { panic(err) }
os.rmdir(folder) or { panic(err) }
}
fn test_cp() {
old_file_name := 'cp_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') }
old_file := os.read_file(old_file_name) or { panic(err) }
new_file := os.read_file(new_file_name) or { panic(err) }
assert old_file == new_file
os.rm(old_file_name)
os.rm(new_file_name)
os.rm(old_file_name) or { panic(err) }
os.rm(new_file_name) or { panic(err) }
}
fn test_mv() {
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
tfile1 := os.join_path(work_dir, 'file')
tfile2 := os.join_path(work_dir, 'file.test')
tfile3 := os.join_path(work_dir, 'file.3')
tfile_content := 'temporary file'
os.write_file(tfile1, tfile_content)
os.write_file(tfile2, tfile_content)
os.write_file(tfile1, tfile_content) or { panic(err) }
os.write_file(tfile2, tfile_content) or { panic(err) }
// Setup test dirs
tdir1 := os.join_path(work_dir, 'dir')
tdir2 := os.join_path(work_dir, 'dir2')
tdir3 := os.join_path(work_dir, 'dir3')
mkdir(tdir1)
mkdir(tdir2)
os.mkdir(tdir1) or { panic(err) }
os.mkdir(tdir2) or { panic(err) }
// 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')
assert os.exists(expected) && !is_dir(expected) == true
// Move dir with contents to other dir
os.mv(tdir1, tdir2)
os.mv(tdir1, tdir2) or { panic(err) }
expected = os.join_path(tdir2, 'dir')
assert os.exists(expected) && is_dir(expected) == true
expected = os.join_path(tdir2, 'dir', 'file')
assert os.exists(expected) && !is_dir(expected) == true
// 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
assert os.exists(expected) && is_dir(expected) == true
assert os.is_dir_empty(tdir2) == true
// Move file with extension to dir
os.mv(tfile2, tdir2)
os.mv(tfile2, tdir2) or { panic(err) }
expected = os.join_path(tdir2, 'file.test')
assert os.exists(expected) && !is_dir(expected) == true
// 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
assert os.exists(expected) && !is_dir(expected) == true
}
@ -253,14 +253,14 @@ fn test_mv() {
fn test_cp_r() {
// fileX -> dir/fileX
// 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.cp_all('ex1.txt', 'ex', false) or { panic(err) }
old := os.read_file('ex1.txt') or { panic(err) }
new := os.read_file('ex/ex1.txt') or { panic(err) }
assert old == new
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) }
old2 := os.read_file('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 os.is_dir(t)
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'
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) }
assert tfile_content_read == tfile_content
os.rm(tfile)
os.rm(tfile) or { panic(err) }
}
fn test_is_writable_folder() {
@ -299,15 +299,15 @@ fn test_make_symlink_check_is_link_and_remove_symlink() {
}
folder := 'tfolder'
symlink := 'tsymlink'
os.rm(symlink)
os.rm(folder)
os.rm(symlink) or { }
os.rm(folder) or { }
os.mkdir(folder) or { panic(err) }
folder_contents := os.ls(folder) or { panic(err) }
assert folder_contents.len == 0
os.system('ln -s $folder $symlink')
assert os.is_link(symlink) == true
os.rm(symlink)
os.rm(folder)
os.rm(symlink) or { panic(err) }
os.rm(folder) or { panic(err) }
folder_exists := os.is_dir(folder)
assert folder_exists == false
symlink_exists := os.is_link(symlink)
@ -343,8 +343,8 @@ fn test_symlink() {
os.symlink('symlink', 'symlink2') or { panic(err) }
assert os.exists('symlink2')
// cleanup
os.rm('symlink')
os.rm('symlink2')
os.rm('symlink') or { panic(err) }
os.rm('symlink2') or { panic(err) }
}
fn test_is_executable_writable_readable() {
@ -367,7 +367,7 @@ fn test_is_executable_writable_readable() {
assert os.is_executable(file_name)
}
// We finally delete the test file.
os.rm(file_name)
os.rm(file_name) or { panic(err) }
}
fn test_ext() {
@ -438,7 +438,7 @@ fn test_write_file_array_bytes() {
for i in 0 .. maxn {
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) }
assert arr == rarr
// eprintln(arr.str())
@ -451,7 +451,7 @@ fn test_write_file_array_structs() {
for i in 0 .. maxn {
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)
assert rarr == arr
assert rarr.len == maxn
@ -519,6 +519,6 @@ fn test_posix_set_bit() {
}
mode = u32(s.st_mode) & 0o7777
assert mode == 0o0755
rm(fpath)
rm(fpath) or { }
}
}

View File

@ -9,9 +9,10 @@ import time
#include <termios.h>
#include <sys/ioctl.h>
#include <signal.h>
fn C.tcgetattr()
fn C.tcsetattr()
fn C.ioctl(fd int, request u64, arg voidptr) int
struct C.termios {
@ -103,7 +104,6 @@ fn (mut ctx Context) termios_setup() ? {
// feature-test rgb (truecolor) support
ctx.enable_rgb = supports_truecolor()
}
// Prevent stdin from blocking by making its read time 0
termios.c_cc[C.VTIME] = 0
termios.c_cc[C.VMIN] = 0
@ -124,7 +124,7 @@ fn (mut ctx Context) termios_setup() ? {
os.signal(C.SIGCONT, fn () {
mut c := ctx_ptr
if c != 0 {
c.termios_setup()
c.termios_setup() or { panic(err) }
c.window_height, c.window_width = get_terminal_size()
mut event := &Event{
typ: .resized
@ -136,7 +136,7 @@ fn (mut ctx Context) termios_setup() ? {
}
})
for code in ctx.cfg.reset {
os.signal(code, fn() {
os.signal(code, fn () {
mut c := ctx_ptr
if c != 0 {
c.cleanup()
@ -145,7 +145,7 @@ fn (mut ctx Context) termios_setup() ? {
})
}
os.signal(C.SIGWINCH, fn() {
os.signal(C.SIGWINCH, fn () {
mut c := ctx_ptr
if c != 0 {
c.window_height, c.window_width = get_terminal_size()
@ -166,10 +166,14 @@ fn get_cursor_position() (int, int) {
print('\033[6n')
buf := malloc(25)
len := C.read(C.STDIN_FILENO, buf, 24)
unsafe { buf[len] = 0 }
unsafe {
buf[len] = 0
}
s := tos(buf, len)
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()
}
@ -184,14 +188,16 @@ fn supports_truecolor() bool {
print('\x1bP\$qm\x1b\\')
buf := malloc(25)
len := C.read(C.STDIN_FILENO, buf, 24)
unsafe { buf[len] = 0 }
unsafe {
buf[len] = 0
}
s := tos(buf, len)
return '1:2:3' in s
}
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')
c := ctx_ptr
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
fn (mut ctx Context) termios_loop() {
frame_time := 1_000_000 / ctx.cfg.frame_rate
@ -221,7 +226,8 @@ fn (mut ctx Context) termios_loop() {
sw.restart()
if ctx.cfg.event_fn != voidptr(0) {
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)
}
if ctx.read_buf.len > 0 {
@ -243,7 +249,9 @@ fn (mut ctx Context) parse_events() {
mut nr_iters := 0
for ctx.read_buf.len > 0 {
nr_iters++
if nr_iters > 100 { ctx.shift(1) }
if nr_iters > 100 {
ctx.shift(1)
}
mut event := &Event(0)
if ctx.read_buf[0] == 0x1b {
e, len := escape_sequence(ctx.read_buf.bytestr())
@ -272,41 +280,52 @@ fn single_char(buf string) &Event {
match ch {
// special handling for `ctrl + letter`
// TODO: Fix assoc in V and remove this workaround :/
// 1 ... 26 { event = Event{ ...event, code: KeyCode(96 | ch), modifiers: ctrl } }
// 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
// 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 } }
65 ... 90 { event = &Event{ typ: event.typ, ascii: event.ascii, utf8: event.utf8, code: KeyCode(32 | ch), modifiers: shift } }
1...8, 11...26 { event = &Event{
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 {}
}
return event
}
[inline]
// Gets an entire, independent escape sequence from the buffer
// Normally, this just means reading until the first letter, but there are some exceptions...
fn escape_end(buf string) int {
mut i := 0
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] == `O` && i + 2 <= buf.len {
n := buf[i+1]
n := buf[i + 1]
if (n >= `A` && n <= `D`) || (n >= `P` && n <= `S`) || n == `F` || n == `H` {
return i + 2
}
}
return i + 1
// 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++
}
// this point should be unreachable
@ -339,32 +358,49 @@ fn escape_sequence(buf_ string) (&Event, int) {
modifiers: c.modifiers | alt
}, 2
}
// ----------------
// Mouse events
// ----------------
// Documentation: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
if buf.len > 2 && buf[1] == `<` {
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()
lo := typ & 0b00011
hi := typ & 0b11100
mut modifiers := u32(0)
if hi & 4 != 0 { modifiers |= shift }
if hi & 8 != 0 { modifiers |= alt }
if hi & 16 != 0 { modifiers |= ctrl }
if hi & 4 != 0 {
modifiers |= shift
}
if hi & 8 != 0 {
modifiers |= alt
}
if hi & 16 != 0 {
modifiers |= ctrl
}
match typ {
0...31 {
last := buf[buf.len - 1]
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 {
button, event := if lo < 3 {
@ -373,17 +409,34 @@ fn escape_sequence(buf_ string) (&Event, int) {
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 {
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
} else {
return &Event{ typ: .unknown, utf8: single }, end
return &Event{
typ: .mouse_scroll
x: x
y: y
direction: direction
modifiers: modifiers
utf8: single
}, end
}
else {
return &Event{
typ: .unknown
utf8: single
}, end
}
}
}
// ----------------------------
// 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)')
output2 := b.gen_c(v_files)
mut f := os.create(out_file) or { panic(err) }
f.writeln(output2)
f.writeln(output2) or { panic(err) }
f.close()
// 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_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 }
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,
bundle_name, 1))
bundle_name, 1)) or { panic(err) }
}
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 {
eprintln('>> remove tmp file: $tmpfile')
}
os.rm(tmpfile)
os.rm(tmpfile) or { panic(err) }
}
}
return
@ -414,7 +414,9 @@ fn (mut v Builder) setup_output_name() {
if v.pref.is_verbose {
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)
}
@ -734,7 +736,7 @@ fn (mut b Builder) cc_linux_cross() {
b.setup_output_name()
parent_dir := os.vmodules_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')
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
// the best we can do for them is just copy them,
// and hope that they work with any compiler...
os.cp(obj_path, opath)
os.cp(obj_path, opath) or { panic(err) }
return
}
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)
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)
}

View File

@ -93,12 +93,12 @@ fn (mut b Builder) run_compiled_executable_and_exit() {
}
if b.pref.os == .ios {
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()
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' }
os.exec('xcrun simctl launch $device $bundle_id')
os.exec('xcrun simctl launch $device $bundle_id') or { panic(err) }
} else {
exefile := os.real_path(b.pref.out_name)
mut cmd := '"$exefile"'
@ -133,7 +133,7 @@ fn (mut v Builder) cleanup_run_executable_after_exit(exefile string) {
}
if os.is_file(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)')
output := b.gen_js(v_files)
mut f := os.create(out_file) or { panic(err) }
f.writeln(output)
f.writeln(output) or { panic(err) }
f.close()
}

View File

@ -315,7 +315,7 @@ pub fn (mut v Builder) cc_msvc() {
// println(res)
// println('C OUTPUT:')
// 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) {

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.return_type.has_flag(.optional) {
if expr.or_block.kind == .absent {
if ret_type != table.void_type {
c.error('${expr.name}() returns an option but is missing an `or {}` block',
c.error('${expr.name}() returns an option, so it should have either an `or {}` block, or `?` at the end',
expr.pos)
}
} else {
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{}
16 | for _ in 0 .. 4 {
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

@ -13,7 +13,7 @@ const skip_files = [
const skip_on_ubuntu_musl = [
'vlib/v/checker/tests/vweb_tmpl_used_var.vv',
]
]
const turn_off_vcolors = os.setenv('VCOLORS', 'never', true)
@ -179,7 +179,7 @@ fn (mut task TaskDescription) execute() {
res := os.exec(cli_cmd) or { panic(err) }
expected_out_path := program.replace('.vv', '') + task.result_extension
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) }
task.expected = clean_line_endings(expected)
@ -192,7 +192,7 @@ fn (mut task TaskDescription) execute() {
if task.expected != task.found___ {
task.is_error = true
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
}
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))
continue
}

View File

@ -58,7 +58,7 @@ fn test_fmt() {
continue
}
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))
continue
}

View File

@ -56,7 +56,7 @@ fn test_vlib_fmt() {
continue
}
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))
continue
}

View File

@ -7,7 +7,7 @@ const (
)
fn testsuite_end() {
os.rmdir_all(main.output_dir)
os.rmdir_all(output_dir) or { }
}
const there_is_node_available = is_nodejs_working()
@ -15,22 +15,22 @@ const there_is_node_available = is_nodejs_working()
fn test_example_compilation() {
vexe := os.getenv('VEXE')
os.chdir(os.dir(vexe))
os.mkdir_all(main.output_dir)
os.mkdir_all(output_dir) or { panic(err) }
files := find_test_files()
for file in files {
path := os.join_path(main.test_dir, file)
path := os.join_path(test_dir, 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 {
assert false
}
// Compilation failed
assert v_code == 0
if !main.there_is_node_available {
if !there_is_node_available {
println(' ... skipping running $file, there is no NodeJS present')
continue
}
js_code := os.system('node $main.output_dir${file}.js')
js_code := os.system('node $output_dir${file}.js')
if js_code != 0 {
assert false
}
@ -40,7 +40,7 @@ fn test_example_compilation() {
}
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
mut tests := files.filter(it.ends_with('.v')).filter(it != 'life.v')
tests.sort()

View File

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

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,
// 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.
os.write_file(tmp_file, source)
os.mv(tmp_file, source_file)
os.write_file(tmp_file, source) or { panic(err) }
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,
res_stop_file,
] {
os.rm(f)
os.rm(f) or { }
}
atomic_write_source(live_program_source)
}
@ -105,7 +105,7 @@ fn testsuite_end() {
assert histogram['CHANGED'] + histogram['ANOTHER'] > 0
// assert histogram['END'] > 0
for tfile in cleanup_files {
os.rm(tfile)
os.rm(tfile) or { }
}
}

View File

@ -9,9 +9,12 @@ fn append_to_file(fname string, s string) {
println('>>>> could not open file $fname for appending, err: $err ')
return
}
f.writeln(s)
//info := live.info()
//f.writeln('>>> reloads: ${info.reloads} | ok reloads: ${info.reloads_ok}')
f.writeln(s) or {
println('>>>> could not write to $fname, err: $err ')
return
}
// info := live.info()
// f.writeln('>>> reloads: ${info.reloads} | ok reloads: ${info.reloads_ok}')
f.close()
}
@ -29,6 +32,7 @@ fn pmessage() string {
const (
delay = 20
)
fn edefault(name string, default string) string {
res := os.getenv(name)
if res == '' {
@ -36,6 +40,7 @@ fn edefault(name string, default string) string {
}
return res
}
fn main() {
mut info := live.info()
info.recheck_period_ms = 5
@ -45,7 +50,7 @@ fn main() {
pmessage()
max_cycles := edefault('LIVE_CYCLES', '1').int()
// NB: 1000 * 20 = maximum of ~20s runtime
for i:=0; i<max_cycles; i++ {
for i := 0; i < max_cycles; i++ {
s := pmessage()
myprintln(s)
append_to_file(os.resource_abs_path(s + '.txt'), s)

View File

@ -112,7 +112,10 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
if op == .decl_assign {
// a, b := a + 1, b
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 {
// a, b = b, a

View File

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

View File

@ -155,7 +155,7 @@ fn (mut pc PkgConfig) resolve(pkgname string) ?string {
}
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 }
return v0.gt(v1)
}
@ -207,8 +207,8 @@ fn (mut pc PkgConfig) load_require(dep string) ? {
if !pcdep.parse(depfile) {
return error('required file "$depfile" could not be parsed')
}
pcdep.load_requires() or { return error(err) }
pc.extend(pcdep)
pcdep.load_requires() ?
pc.extend(pcdep) ?
}
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() {
if pc.options.use_default_paths {
for path in default_paths {
for path in pkgconfig.default_paths {
pc.add_path(path)
}
}

View File

@ -474,10 +474,10 @@ pub fn parse_args(args []string) (&Preferences, string) {
//
if output_option.len != 0 {
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')
os.rm(tmp_v_file_path)
os.rm(tmp_v_file_path) or { panic(err) }
exit(tmp_result)
}
must_exist(res.path)

View File

@ -33,13 +33,13 @@ fn test_all() {
panic(err)
}
$if windows {
os.rm('./test.exe')
os.rm('./test.exe') or { }
$if msvc {
os.rm('./test.ilk')
os.rm('./test.pdb')
os.rm('./test.ilk') or { }
os.rm('./test.pdb') or { }
}
} $else {
os.rm('./test')
os.rm('./test') or { }
}
// println('============')
// 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
tfolder := os.join_path(cdir, 'vrepl_tests_$idx')
if os.is_dir(tfolder) {
os.rmdir_all(tfolder)
os.rmdir_all(tfolder) or { panic(err) }
}
os.mkdir(tfolder) or { panic(err) }
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 {
session.bmark.fail()
tls_bench.fail()
os.rmdir_all(tfolder)
os.rmdir_all(tfolder) or { panic(err) }
eprintln(tls_bench.step_message_fail(err))
assert false
return sync.no_result
}
session.bmark.ok()
tls_bench.ok()
os.rmdir_all(tfolder)
os.rmdir_all(tfolder) or { panic(err) }
println(tls_bench.step_message_ok(fres))
assert true
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 {
diffcmd := util.find_working_diff_command() or {
return err
}
diffcmd := util.find_working_diff_command() or { return err }
return util.color_compare_files(diffcmd, file_result, file_expected)
}
pub fn run_repl_file(wd string, vexec string, file string) ?string {
vexec_folder := os.dir(vexec) + os.path_separator
fcontent := os.read_file(file) or {
return error('Could not read file $file')
}
fcontent := os.read_file(file) or { return error('Could not read file $file') }
content := fcontent.replace('\r', '')
input := content.all_before('===output===\n')
output := content.all_after('===output===\n').trim_right('\n\r')
fname := os.file_name(file)
input_temporary_filename := os.real_path(os.join_path(wd, 'input_temporary_filename.txt'))
os.write_file(input_temporary_filename, input)
os.write_file(os.real_path(os.join_path(wd, 'original.txt')), fcontent)
os.write_file(input_temporary_filename, input) or { panic(err) }
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'
r := os.exec(rcmd) or {
os.rm(input_temporary_filename)
os.rm(input_temporary_filename) or { panic(err) }
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('... ',
'').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 {
file_result := '${file}.result.txt'
file_expected := '${file}.expected.txt'
os.write_file(file_result, result)
os.write_file(file_expected, output)
os.write_file(file_result, result) or { panic(err) }
os.write_file(file_expected, output) or { panic(err) }
diff := diff_files(file_result, file_expected)
return error('Difference found in REPL file: $file
====> Got :
@ -87,16 +84,14 @@ pub fn run_prod_file(wd string, vexec string, file string) ?string {
}
expected_content := f_expected_content.replace('\r', '')
cmd := '"$vexec" -prod run "$file"'
r := os.exec(cmd) or {
return error('Could not execute: $cmd')
}
r := os.exec(cmd) or { return error('Could not execute: $cmd') }
if r.exit_code != 0 {
return error('$cmd return exit code: $r.exit_code')
}
result := r.output.replace('\r', '')
if result != expected_content {
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)
return error('Difference found in test: $file
====> Got :

View File

@ -19,7 +19,7 @@ fn pipe_to_v_run() ? {
// eprintln('>> cmd: $cmd | res: $res')
assert res.exit_code == 0
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)
}

View File

@ -53,13 +53,11 @@ fn test_all() {
files := os.ls(dir) or { panic(err) }
//
wrkdir := os.join_path(os.temp_dir(), 'vtests', 'valgrind')
os.mkdir_all(wrkdir)
os.mkdir_all(wrkdir) or { panic(err) }
os.chdir(wrkdir)
//
tests := vtest.filter_vtest_only(files.filter(it.ends_with('.v') && !it.ends_with('_test.v')),
basepath: valgrind_test_path
)
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)
bench.set_total_expected_steps(tests.len)
for test in tests {
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()
e_file := os.join_path(cdir, '${ctime}.expected.txt')
f_file := os.join_path(cdir, '${ctime}.found.txt')
os.write_file(e_file, expected)
os.write_file(f_file, found)
os.write_file(e_file, expected) or { panic(err) }
os.write_file(f_file, found) or { panic(err) }
res := color_compare_files(diff_cmd, e_file, f_file)
os.rm(e_file)
os.rm(f_file)
os.rm(e_file) or { panic(err) }
os.rm(f_file) or { panic(err) }
return res
}

View File

@ -489,7 +489,7 @@ pub fn get_vtmp_folder() string {
}
vtmp = os.join_path(os.temp_dir(), 'v')
if !os.exists(vtmp) || !os.is_dir(vtmp) {
os.mkdir_all(vtmp)
os.mkdir_all(vtmp) or { panic(err) }
}
os.setenv('VTMP', vtmp, true)
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')
}
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.
|You can safely delete it, if it is getting too large.
|It will be recreated the next time you compile something with V.
|You can change its location with the VCACHE environment variable.
'.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('|')
return CacheManager{
@ -74,7 +74,7 @@ pub fn (mut cm CacheManager) key2cpath(key string) string {
cprefix_folder := os.join_path(cm.basepath, prefix)
cpath = os.join_path(cprefix_folder, khash)
if !os.is_dir(cprefix_folder) {
os.mkdir_all(cprefix_folder)
os.mkdir_all(cprefix_folder) or { panic(err) }
os.chmod(cprefix_folder, 0o777)
}
cm.k2cpath[key] = cpath

View File

@ -17,7 +17,7 @@ fn check_cache_entry_fpath_invariants(x string, extension string) {
fn testsuite_begin() {
os.setenv('VCACHE', vcache_folder, true)
// eprintln('testsuite_begin, vcache_folder = $vcache_folder')
os.rmdir_all(vcache_folder)
os.rmdir_all(vcache_folder) or { }
vcache.new_cache_manager([])
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() {
mut cm := vcache.new_cache_manager([])
cm.exists('.o', 'abc') or {
assert true
}
cm.exists('.o', 'abc') or { assert true }
//
x := cm.save('.x', 'abc', '') or {
assert false
''
}
cm.exists('.o', 'abc') or {
assert true
}
cm.exists('.o', 'abc') or { assert true }
//
y := cm.save('.o', 'zbc', '') or {
assert false
''
}
cm.exists('.o', 'abc') or {
assert true
}
cm.exists('.o', 'abc') or { assert true }
//
z := cm.save('.o', 'abc', '') or {
assert false
''
}
cm.exists('.o', 'abc') or {
assert false
}
cm.exists('.o', 'abc') or { assert false }
//
assert os.is_file(x)
assert os.is_file(y)
@ -104,6 +96,6 @@ fn test_readme_exists_and_is_readable() {
fn testsuite_end() {
os.chdir(os.wd_at_startup)
os.rmdir_all(vcache_folder)
os.rmdir_all(vcache_folder) or { }
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) }
}
mut file := os.create(out_file) or { panic(err) }
file.write(out.bytes())
file.write(out.bytes()) or { panic(err) }
file.close()
return out_file
}

View File

@ -6,7 +6,7 @@ import os
// unique cache dirs are needed per test function.
fn clean_cache_dir(dir string) {
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 {
path := os.join_path(base_cache_dir(), file)
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) {
os.write_file(path, get_test_file_contents(file))
os.write_file(path, get_test_file_contents(file)) or { panic(err) }
}
return path
}

View File

@ -20,7 +20,7 @@ const (
fn testsuite_begin() {
os.chdir(vroot)
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_write_timeout(tcp_w_timeout)
defer {
client.close()
client.close() or { }
}
message := 'GET $config.path HTTP/1.1
Host: $config.host

View File

@ -355,7 +355,8 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
//}
// read body
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()
break
}

View File

@ -1,4 +1,5 @@
module ttf
/**********************************************************************
*
* Common data for the module
@ -15,8 +16,7 @@ import os
import math
// text align
pub
enum Text_align {
pub enum Text_align {
left
center
right
@ -24,8 +24,7 @@ enum Text_align {
}
// draw style
pub
enum Style {
pub enum Style {
outline
outline_aliased
filled
@ -38,8 +37,9 @@ enum Style {
*
******************************************************************************/
const debug_flag = false
fn dprintln(txt string){
if debug_flag {
fn dprintln(txt string) {
if ttf.debug_flag {
println(txt)
}
}
@ -50,34 +50,34 @@ fn dprintln(txt string){
*
******************************************************************************/
// transform the bitmap from one layer to color layers
fn (mut bmp BitMap) format_texture(){
fn (mut bmp BitMap) format_texture() {
r := byte(bmp.color >> 24)
g := byte((bmp.color >> 16) & 0xFF)
b := byte((bmp.color >> 8 ) & 0xFF)
b := byte((bmp.color >> 8) & 0xFF)
a := byte(bmp.color & 0xFF)
b_r := byte(bmp.bg_color >> 24)
b_g := byte((bmp.bg_color >> 16) & 0xFF)
b_b := byte((bmp.bg_color >> 8 ) & 0xFF)
b_b := byte((bmp.bg_color >> 8) & 0xFF)
b_a := byte(bmp.bg_color & 0xFF)
// trasform buffer in a texture
x := byteptr(bmp.buf)
unsafe{
unsafe {
mut i := 0
for i<bmp.buf_size {
for i < bmp.buf_size {
data := x[i]
if data > 0 {
x[i+0] = r
x[i+1] = g
x[i+2] = b
x[i + 0] = r
x[i + 1] = g
x[i + 2] = b
// alpha
x[i+3] = byte((a * data) >> 8)
x[i + 3] = byte((a * data) >> 8)
} else {
x[i+0] = b_r
x[i+1] = b_g
x[i+2] = b_b
x[i+3] = b_a
x[i + 0] = b_r
x[i + 1] = b_g
x[i + 2] = b_b
x[i + 3] = b_a
}
i += 4
}
@ -85,8 +85,7 @@ fn (mut bmp BitMap) format_texture(){
}
// write out a .ppm file
pub
fn (mut bmp BitMap) save_as_ppm(file_name string) {
pub fn (mut bmp BitMap) save_as_ppm(file_name string) {
tmp_buf := bmp.buf
mut buf := malloc(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()
npixels := bmp.width * bmp.height
mut f_out := os.create(file_name) or { panic(err) }
f_out.writeln('P3')
f_out.writeln('${bmp.width} ${bmp.height}')
f_out.writeln('255')
for i in 0..npixels {
f_out.writeln('P3') or { panic(err) }
f_out.writeln('$bmp.width $bmp.height') or { panic(err) }
f_out.writeln('255') or { panic(err) }
for i in 0 .. npixels {
pos := i * bmp.bp
unsafe {
c_r := bmp.buf[pos]
c_g := bmp.buf[pos +1 ]
c_g := bmp.buf[pos + 1]
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()
@ -114,23 +112,22 @@ fn (mut bmp BitMap) save_as_ppm(file_name string) {
bmp.buf = tmp_buf
}
pub
fn (mut bmp BitMap) get_raw_bytes() []byte {
mut f_buf := []byte{len: bmp.buf_size/4}
mut i:=0
pub fn (mut bmp BitMap) get_raw_bytes() []byte {
mut f_buf := []byte{len: bmp.buf_size / 4}
mut i := 0
for i < bmp.buf_size {
unsafe { f_buf[i>>2] = *(bmp.buf + i) }
unsafe {
f_buf[i >> 2] = *(bmp.buf + i)
}
i += 4
}
return f_buf
}
pub
fn (mut bmp BitMap) save_raw_data(file_name string) {
os.write_file_array(file_name, bmp.get_raw_bytes())
pub fn (mut bmp BitMap) save_raw_data(file_name string) {
os.write_file_array(file_name, bmp.get_raw_bytes()) or { panic(err) }
}
//
// Math functions
//
@ -181,8 +178,7 @@ fn rfpart(x f32) f32 {
******************************************************************************/
/*
[inline]
pub
fn (mut dev BitMap) get_color(x int, y int) (int, int, int, int){
pub 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 {
return 0,0,0,0
}
@ -193,8 +189,7 @@ fn (mut dev BitMap) get_color(x int, y int) (int, int, int, int){
}
[inline]
pub
fn (mut dev BitMap) get_color_u32(x int, y int) u32{
pub fn (mut dev BitMap) get_color_u32(x int, y int) u32{
r, g, b, a := dev.get_color(x, y)
unsafe{
return u32(r<<24) | u32(g<<16) | u32(b<<8) | u32(a)
@ -207,18 +202,16 @@ fn (mut dev BitMap) get_color_u32(x int, y int) u32{
*
******************************************************************************/
[inline]
pub
fn color_multiply_alpha(c u32, level f32) u32 {
return u32(f32( c & 0xFF) * level)
pub fn color_multiply_alpha(c u32, level f32) u32 {
return u32(f32(c & 0xFF) * level)
}
[inline]
pub
fn color_multiply(c u32, level f32) u32 {
mut r := (f32((c >> 24) & 0xFF)/255.0) * level
mut g := (f32((c >> 16) & 0xFF)/255.0) * level
mut b := (f32((c >> 8) & 0xFF)/255.0) * level
mut a := (f32( c & 0xFF)/255.0) * level
pub fn color_multiply(c u32, level f32) u32 {
mut r := (f32((c >> 24) & 0xFF) / 255.0) * level
mut g := (f32((c >> 16) & 0xFF) / 255.0) * level
mut b := (f32((c >> 8) & 0xFF) / 255.0) * level
mut a := (f32(c & 0xFF) / 255.0) * level
r = if r > 1.0 { 1.0 } else { r }
g = if g > 1.0 { 1.0 } else { g }
b = if b > 1.0 { 1.0 } else { b }

View File

@ -1,4 +1,5 @@
module ttf
/**********************************************************************
*
* BMP render module utility functions
@ -15,40 +16,31 @@ module ttf
import encoding.utf8
import math
pub
struct BitMap {
pub struct BitMap {
pub mut:
tf &TTF_File
buf byteptr // pointer to the memory buffer
buf_size int // allocated buf size in bytes
width int =1 // width of the buffer
height int =1 // height of the buffer
bp int =4 // byte per pixel of the buffer
width int = 1 // width of the buffer
height int = 1 // height of the buffer
bp int = 4 // byte per pixel of the buffer
bg_color u32 = 0xFFFFFF_00 // background RGBA format
color u32 = 0x000000_FF // RGBA format
scale f32 = 1.0 // internal usage!!
scale_x f32 = 1.0 // X 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
// spaces
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!!
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
style Style = .filled // default syle
align Text_align = .left // default text align
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
filler [][]int // filler buffer for the renderer
// flag to force font embedded metrics
use_font_metrics bool
}
@ -59,8 +51,7 @@ pub mut:
*
******************************************************************************/
// clear clear the bitmap with 0 bytes
pub
fn (mut bmp BitMap) clear() {
pub fn (mut bmp BitMap) clear() {
mut sz := bmp.width * bmp.height * bmp.bp
unsafe {
C.memset(bmp.buf, 0x00, sz)
@ -69,30 +60,28 @@ fn (mut bmp BitMap) clear() {
// transform matrix applied to the text
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]),
int(p.x * bmp.tr_matrix[1] + p.y * bmp.tr_matrix[4] + bmp.tr_matrix[7])
return int(p.x * bmp.tr_matrix[0] + p.y * bmp.tr_matrix[3] + bmp.tr_matrix[6]), int(
p.x * bmp.tr_matrix[1] + p.y * bmp.tr_matrix[4] + bmp.tr_matrix[7])
}
// transform matrix applied to the char
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]),
int(p.x * bmp.ch_matrix[1] + p.y * bmp.ch_matrix[4] + bmp.ch_matrix[7])
return int(p.x * bmp.ch_matrix[0] + p.y * bmp.ch_matrix[3] + bmp.ch_matrix[6]), int(
p.x * bmp.ch_matrix[1] + p.y * bmp.ch_matrix[4] + bmp.ch_matrix[7])
}
// set draw postion in the buffer
pub
fn (mut bmp BitMap) set_pos(x f32, y f32) {
pub fn (mut bmp BitMap) set_pos(x f32, y f32) {
bmp.tr_matrix[6] = x
bmp.tr_matrix[7] = y
}
// set the rotation angle in radiants
pub
fn (mut bmp BitMap) set_rotation(a f32) {
bmp.tr_matrix[0] = f32(math.cos(a)) //1
bmp.tr_matrix[1] = f32(-math.sin(a)) //0
bmp.tr_matrix[3] = f32(math.sin(a)) //0
bmp.tr_matrix[4] = f32(math.cos(a)) //1
pub fn (mut bmp BitMap) set_rotation(a f32) {
bmp.tr_matrix[0] = f32(math.cos(a)) // 1
bmp.tr_matrix[1] = f32(-math.sin(a)) // 0
bmp.tr_matrix[3] = f32(math.sin(a)) // 0
bmp.tr_matrix[4] = f32(math.cos(a)) // 1
}
/******************************************************************************
@ -100,43 +89,40 @@ fn (mut bmp BitMap) set_rotation(a f32) {
* Filler functions
*
******************************************************************************/
pub
fn (mut bmp BitMap) init_filler() {
pub fn (mut bmp BitMap) init_filler() {
h := bmp.height - bmp.filler.len
if h < 1 {
return
}
for _ in 0..h {
bmp.filler << []int{len:4}
for _ in 0 .. h {
bmp.filler << []int{len: 4}
}
// dprintln("Init filler: ${bmp.filler.len} rows")
}
pub
fn (mut bmp BitMap) clear_filler() {
for i in 0..bmp.height {
pub fn (mut bmp BitMap) clear_filler() {
for i in 0 .. bmp.height {
bmp.filler[i].clear()
}
}
pub
fn (mut bmp BitMap) exec_filler() {
for y in 0..bmp.height {
pub fn (mut bmp BitMap) exec_filler() {
for y in 0 .. bmp.height {
if bmp.filler[y].len > 0 {
bmp.filler[y].sort()
if bmp.filler[y].len & 1 != 0 {
//dprintln("even line!! $y => ${bmp.filler[y]}")
// dprintln("even line!! $y => ${bmp.filler[y]}")
continue
}
mut index := 0
for index < bmp.filler[y].len {
startx := bmp.filler[y][index] + 1
endx := bmp.filler[y][index+1]
endx := bmp.filler[y][index + 1]
if startx >= endx {
index += 2
continue
}
for x in startx..endx {
for x in startx .. endx {
bmp.plot(x, y, bmp.color)
}
index += 2
@ -145,8 +131,7 @@ fn (mut bmp BitMap) exec_filler() {
}
}
pub
fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
pub 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 x1 := f32(in_x1)
mut y0 := f32(in_y0)
@ -184,15 +169,15 @@ fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
return
}
mut n := dx / dy
for y in 0..int(dy+0.5) {
for y in 0 .. int(dy + 0.5) {
yd := int(y + y0)
x := n * y + x0
if x > bmp.width || yd >= bmp.filler.len {
break
}
if yd >= 0 && yd < bmp.filler.len {
bmp.filler[yd] << int(x+0.5)
//bmp.plot(int(x+0.5), yd, bmp.color)
bmp.filler[yd] << int(x + 0.5)
// bmp.plot(int(x+0.5), yd, bmp.color)
}
}
}
@ -203,23 +188,22 @@ fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
*
******************************************************************************/
[inline]
pub
fn (mut bmp BitMap) plot(x int, y int, c u32) bool {
pub fn (mut bmp BitMap) plot(x int, y int, c u32) bool {
if x < 0 || x >= bmp.width || y < 0 || y >= bmp.height {
return false
}
mut index := (x + y * bmp.width) * bmp.bp
unsafe {
//bmp.buf[index]=0xFF
// bmp.buf[index]=0xFF
bmp.buf[index] = byte(c & 0xFF) // write only the alpha
}
/*
/*
for count in 0..(bmp.bp) {
unsafe{
bmp.buf[index + count] = byte((c >> (bmp.bp - count - 1) * 8) & 0x0000_00FF)
}
}
*/
*/
return true
}
@ -229,9 +213,8 @@ fn (mut bmp BitMap) plot(x int, y int, c u32) bool {
*
******************************************************************************/
// aline draw an aliased line on the bitmap
pub
fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
//mut c1 := c
pub fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
// mut c1 := c
mut x0 := f32(in_x0)
mut x1 := f32(in_x1)
mut y0 := f32(in_y0)
@ -263,11 +246,11 @@ fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
mut x := x0
for x <= x1 + 0.5 {
y := m * (x - x0) + y0
e := 1-fabs(y-0.5-int(y))
bmp.plot(int(x), int(y), color_multiply_alpha(c, e*0.75))
e := 1 - fabs(y - 0.5 - int(y))
bmp.plot(int(x), int(y), color_multiply_alpha(c, e * 0.75))
ys1 := y + dist
if int(ys1) != int(y){
if int(ys1) != int(y) {
v1 := fabs(ys1 - y) / dist * (1 - e)
bmp.plot(int(x), int(ys1), color_multiply_alpha(c, v1))
}
@ -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
}
} else {
if y1 < y0 {
tmp = x0
@ -302,7 +284,7 @@ fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
for y <= y1 + 0.5 {
x := n * (y - y0) + x0
e := f32(1 - fabs(x - 0.5 - int(x)))
bmp.plot(int(x), int(y), color_multiply_alpha(c, f32(e*0.75)))
bmp.plot(int(x), int(y), color_multiply_alpha(c, f32(e * 0.75)))
xs1 := x + dist
if int(xs1) != int(x) {
@ -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
*
******************************************************************************/
pub
fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
pub fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
// outline with aliased borders
if bmp.style == .outline_aliased {
bmp.aline(in_x0, in_y0, in_x1, in_y1, c)
@ -350,7 +330,7 @@ fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
x1 := int(in_x1)
y0 := int(in_y0)
y1 := int(in_y1)
//dprintln("line[$x0,$y0,$x1,$y1]")
// dprintln("line[$x0,$y0,$x1,$y1]")
mut x := x0
mut y := y0
@ -363,24 +343,24 @@ fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
// verical line
if dx == 0 {
if y0 < y1 {
for yt in y0..y1+1 {
for yt in y0 .. y1 + 1 {
bmp.plot(x0, yt, c)
}
return
}
for yt in y1..y0+1 {
for yt in y1 .. y0 + 1 {
bmp.plot(x0, yt, c)
}
return
// horizontal line
} else if dy == 0{
return
} else if dy == 0 {
if x0 < x1 {
for xt in x0..x1+1 {
for xt in x0 .. x1 + 1 {
bmp.plot(xt, y0, c)
}
return
}
for xt in x1..x0+1 {
for xt in x1 .. x0 + 1 {
bmp.plot(xt, y0, c)
}
return
@ -388,10 +368,10 @@ fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32) {
mut err := dx + dy // error value e_xy
for {
//bmp.plot(x, y, u32(0xFF00))
// bmp.plot(x, y, u32(0xFF00))
bmp.plot(x, y, c)
//dprintln("$x $y [$x0,$y0,$x1,$y1]")
// dprintln("$x $y [$x0,$y0,$x1,$y1]")
if x == x1 && y == y1 {
break
}
@ -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
}
}
}
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_x1, in_y0, 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)
}
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) {
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) {
/*
x0 := int(in_x0 * bmp.scale)
x1 := int(in_x1 * bmp.scale)
@ -439,19 +415,19 @@ fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in_cx
dy := abs(y0 - y1)
// if few pixel draw a simple line
//if dx == 0 && dy == 0 {
// if dx == 0 && dy == 0 {
if dx <= 2 || dy <= 2 {
//bmp.plot(x0, y0, c)
bmp.line(x0,y0,x1,y1, c)
// bmp.plot(x0, y0, c)
bmp.line(x0, y0, x1, y1, c)
return
}
division = 1.0/(f64( if dx>dy {dx} else {dy} ))
division = 1.0 / (f64(if dx > dy { dx } else { dy }))
//division = 0.1 // 10 division
//division = 0.25 // 4 division
// division = 0.1 // 10 division
// division = 0.25 // 4 division
//dprintln("div: $division")
// dprintln("div: $division")
/*
----- Bezier quadratic form -----
@ -465,13 +441,13 @@ fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in_cx
mut y_old := y0
mut t := 0.0
for t <= (1.0 + division/2.0){
for t <= (1.0 + division / 2.0) {
s := 1.0 - t
x := s * s * x0 + 2.0 * s * t * cx + t * t * x1
y := s * s * y0 + 2.0 * s * t * cy + t * t * y1
xi := int(x + 0.5)
yi := int(y + 0.5)
//bmp.plot(xi, yi, c)
// bmp.plot(xi, yi, c)
bmp.line(x_old, y_old, xi, yi, c)
x_old = xi
y_old = yi
@ -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
*
******************************************************************************/
pub
fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
pub fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
mut res := []int{}
mut w := 0
@ -505,12 +480,11 @@ fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
i++
continue
}
// 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 {
tmp_char := utf8.get_uchar(in_string,i)
//dprintln("tmp_char: ${tmp_char.hex()}")
tmp_char := utf8.get_uchar(in_string, i)
// dprintln("tmp_char: ${tmp_char.hex()}")
char = u16(tmp_char)
}
@ -522,18 +496,18 @@ fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
continue
}
ax , ay := bmp.tf.next_kern(c_index)
//dprintln("char_index: $c_index ax: $ax ay: $ay")
ax, ay := bmp.tf.next_kern(c_index)
// dprintln("char_index: $c_index ax: $ax ay: $ay")
//cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
//dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
// cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
// dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
//----- Calc Glyph transformations -----
mut x0 := w + int(ax * bmp.scale)
mut y0 := 0 + int(ay * bmp.scale)
p := Point{x0,y0,false}
x1 , y1 := bmp.trf_txt(p)
p := Point{x0, y0, false}
x1, y1 := bmp.trf_txt(p)
// init ch_matrix
bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x
bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x
@ -542,24 +516,23 @@ fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
bmp.ch_matrix[6] = int(x1)
bmp.ch_matrix[7] = int(y1)
//x_min, x_max, y_min, y_max := bmp.tf.read_glyph_dim(c_index)
// x_min, x_max, y_min, y_max := bmp.tf.read_glyph_dim(c_index)
x_min, x_max, _, _ := bmp.tf.read_glyph_dim(c_index)
//-----------------
width := int( (abs(x_max + x_min) + ax) * bmp.scale)
//width := int((cw+ax) * bmp.scale)
width := int((abs(x_max + x_min) + ax) * bmp.scale)
// width := int((cw+ax) * bmp.scale)
w += width + div_space_cw
h := int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
res << w
res << h
i+= c_len
i += c_len
}
return res
}
pub
fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
pub fn (mut bmp BitMap) get_bbox(in_string string) (int, int) {
mut w := 0
mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `))
@ -578,12 +551,11 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
i++
continue
}
// 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 {
tmp_char := utf8.get_uchar(in_string,i)
//dprintln("tmp_char: ${tmp_char.hex()}")
tmp_char := utf8.get_uchar(in_string, i)
// dprintln("tmp_char: ${tmp_char.hex()}")
char = u16(tmp_char)
}
@ -594,18 +566,18 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
i += c_len
continue
}
ax , ay := bmp.tf.next_kern(c_index)
//dprintln("char_index: $c_index ax: $ax ay: $ay")
ax, ay := bmp.tf.next_kern(c_index)
// dprintln("char_index: $c_index ax: $ax ay: $ay")
//cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
//dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
// cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
// dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
//----- Calc Glyph transformations -----
mut x0 := w + int(ax * bmp.scale)
mut y0 := 0 + int(ay * bmp.scale)
p := Point{x0,y0,false}
x1 , y1 := bmp.trf_txt(p)
p := Point{x0, y0, false}
x1, y1 := bmp.trf_txt(p)
// init ch_matrix
bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x
bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x
@ -615,20 +587,20 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
bmp.ch_matrix[7] = int(y1)
x_min, x_max, _, _ := bmp.tf.read_glyph_dim(c_index)
//x_min := 1
//x_max := 2
// x_min := 1
// x_max := 2
//-----------------
width := int( (abs(x_max + x_min) + ax) * bmp.scale)
//width := int((cw+ax) * bmp.scale)
width := int((abs(x_max + x_min) + ax) * bmp.scale)
// width := int((cw+ax) * bmp.scale)
w += width + div_space_cw
i+= c_len
i += c_len
}
//dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}")
//buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) )
return w , int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
// dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}")
// buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) )
return w, int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
}
/******************************************************************************
@ -638,7 +610,7 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
******************************************************************************/
fn (mut bmp BitMap) draw_notdef_glyph(in_x int, in_w int) {
mut p := Point{in_x, 0, false}
x1 , y1 := bmp.trf_txt(p)
x1, y1 := bmp.trf_txt(p)
// init ch_matrix
bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x
bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x
@ -646,17 +618,16 @@ fn (mut bmp BitMap) draw_notdef_glyph(in_x int, in_w int) {
bmp.ch_matrix[4] = bmp.tr_matrix[4] * -bmp.scale * bmp.scale_y
bmp.ch_matrix[6] = int(x1)
bmp.ch_matrix[7] = int(y1)
x,y := bmp.trf_ch(p)
x, y := bmp.trf_ch(p)
y_h := fabs(bmp.tf.y_max-bmp.tf.y_min)* bmp.scale * 0.5
y_h := fabs(bmp.tf.y_max - bmp.tf.y_min) * bmp.scale * 0.5
bmp.box(int(x), int(y), int(x - in_w), int(y - y_h), bmp.color)
bmp.line(int(x), int(y), int(x - in_w ), int(y - y_h), bmp.color)
bmp.line(int(x - in_w ), int(y), int(x), int(y - y_h), bmp.color)
bmp.line(int(x), int(y), int(x - in_w), int(y - y_h), bmp.color)
bmp.line(int(x - in_w), int(y), int(x), int(y - y_h), bmp.color)
}
pub
fn (mut bmp BitMap) draw_text(in_string string) (int, int){
pub fn (mut bmp BitMap) draw_text(in_string string) (int, int) {
mut w := 0
mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `))
@ -675,12 +646,11 @@ fn (mut bmp BitMap) draw_text(in_string string) (int, int){
i++
continue
}
// 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 {
tmp_char := utf8.get_uchar(in_string,i)
//dprintln("tmp_char: ${tmp_char.hex()}")
tmp_char := utf8.get_uchar(in_string, i)
// dprintln("tmp_char: ${tmp_char.hex()}")
char = u16(tmp_char)
}
@ -693,19 +663,19 @@ fn (mut bmp BitMap) draw_text(in_string string) (int, int){
continue
}
ax , ay := bmp.tf.next_kern(c_index)
//dprintln("char_index: $c_index ax: $ax ay: $ay")
ax, ay := bmp.tf.next_kern(c_index)
// dprintln("char_index: $c_index ax: $ax ay: $ay")
cw, _ := bmp.tf.get_horizontal_metrics(u16(char))
//cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
//dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
// cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
// dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
//----- Draw_Glyph transformations -----
mut x0 := w + int(ax * bmp.scale)
mut y0 := 0 + int(ay * bmp.scale)
p := Point{x0,y0,false}
x1 , y1 := bmp.trf_txt(p)
p := Point{x0, y0, false}
x1, y1 := bmp.trf_txt(p)
// init ch_matrix
bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x
bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x
@ -719,21 +689,20 @@ fn (mut bmp BitMap) draw_text(in_string string) (int, int){
// x_max := 2
//-----------------
mut width := int( (abs(x_max + x_min) + ax) * bmp.scale)
mut width := int((abs(x_max + x_min) + ax) * bmp.scale)
if bmp.use_font_metrics {
width = int((cw+ax) * bmp.scale)
width = int((cw + ax) * bmp.scale)
}
w += width + div_space_cw
i+= c_len
i += c_len
}
//dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}")
//buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) )
return w , int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
// dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}")
// buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) )
return w, int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
}
pub
fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
pub fn (mut bmp BitMap) draw_glyph(index u16) (int, int) {
glyph := bmp.tf.read_glyph(index)
if !glyph.valid_glyph {
@ -749,20 +718,20 @@ fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
mut contour_start := 0
mut x0 := 0
mut y0 := 0
color := bmp.color //u32(0xFFFF_FF00) // RGBA white
//color1 := u32(0xFF00_0000) // RGBA red
//color2 := u32(0x00FF_0000) // RGBA green
color := bmp.color // u32(0xFFFF_FF00) // RGBA white
// color1 := u32(0xFF00_0000) // RGBA red
// color2 := u32(0x00FF_0000) // RGBA green
mut sp_x := 0
mut sp_y := 0
mut point := Point{}
for count, point_raw in glyph.points {
//dprintln("count: $count, state: $s pl:$glyph.points.len")
// dprintln("count: $count, state: $s pl:$glyph.points.len")
point.x = point_raw.x
point.y = point_raw.y
point.x , point.y = bmp.trf_ch(point)
point.x, point.y = bmp.trf_ch(point)
point.on_curve = point_raw.on_curve
if s == 0 {
@ -775,69 +744,67 @@ fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
} else if s == 1 {
if point.on_curve {
bmp.line(x0, y0, point.x, point.y, color)
//bmp.aline(x0, y0, point.x, point.y, u32(0xFFFF0000))
// bmp.aline(x0, y0, point.x, point.y, u32(0xFFFF0000))
x0 = point.x
y0 = point.y
} else {
s = 2
}
} else {
//dprintln("s==2")
// dprintln("s==2")
mut prev := glyph.points[count - 1]
prev.x, prev.y = bmp.trf_ch(prev)
if point.on_curve {
//dprintln("HERE1")
// dprintln("HERE1")
// ctx.quadraticCurveTo(prev.x + x, prev.y + y,point.x + x, point.y + y);
//bmp.line(x0, y0, point.x + in_x, point.y + in_y, color1)
//bmp.quadratic(x0, y0, point.x + in_x, point.y + in_y, prev.x + in_x, prev.y + in_y, u32(0xa0a00000))
// bmp.line(x0, y0, point.x + in_x, point.y + in_y, color1)
// bmp.quadratic(x0, y0, point.x + in_x, point.y + in_y, prev.x + in_x, prev.y + in_y, u32(0xa0a00000))
bmp.quadratic(x0, y0, point.x, point.y, prev.x, prev.y, color)
x0 = point.x
y0 = point.y
s = 1
} else {
//dprintln("HERE2")
// dprintln("HERE2")
// ctx.quadraticCurveTo(prev.x + x, prev.y + y,
// (prev.x + point.x) / 2 + x,
// (prev.y + point.y) / 2 + y);
//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, color)
x0 = (prev.x + point.x)/2
y0 = (prev.y + point.y)/2
// 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, color)
x0 = (prev.x + point.x) / 2
y0 = (prev.y + point.y) / 2
}
}
if count == glyph.contour_ends[c] {
//dprintln("count == glyph.contour_ends[count]")
// dprintln("count == glyph.contour_ends[count]")
if s == 2 { // final point was off-curve. connect to start
mut start_point := glyph.points[contour_start]
start_point.x, start_point.y = bmp.trf_ch(start_point)
if point.on_curve {
//ctx.quadraticCurveTo(prev.x + x, prev.y + y,
//point.x + x, point.y + y);
//bmp.line(x0, y0, start_point.x + in_x, start_point.y + in_y, u32(0x00FF0000))
// ctx.quadraticCurveTo(prev.x + x, prev.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.quadratic(x0, y0, start_point.x, start_point.y ,
// 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 {
//ctx.quadraticCurveTo(prev.x + x, prev.y + y,
// ctx.quadraticCurveTo(prev.x + x, prev.y + y,
// (prev.x + point.x) / 2 + x,
// (prev.y + point.y) / 2 + y);
//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))
color)
// bmp.line(x0, y0, start_point.x, start_point.y, u32(0x00FF0000)
// u32(0xFF000000))
bmp.quadratic(x0, y0, start_point.x, start_point.y, (point.x +
start_point.x) / 2, (point.y + start_point.y) / 2, color)
}
} else {
// last point not in a curve
//bmp.line(point.x, point.y, sp_x, sp_y, u32(0x00FF0000))
// bmp.line(point.x, point.y, sp_x, sp_y, u32(0x00FF0000))
bmp.line(point.x, point.y, sp_x, sp_y, color)
}
contour_start = count + 1
@ -853,5 +820,5 @@ fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
x_max := glyph.x_max
return x_min, x_max
//return glyph.x_min, glyph.x_max
// return glyph.x_min, glyph.x_max
}

View File

@ -1,4 +1,5 @@
module ttf
/**********************************************************************
*
* BMP render module utility functions
@ -15,11 +16,9 @@ import math
import gg
import sokol.sgl
pub
struct TTF_render_Sokol {
pub struct TTF_render_Sokol {
pub mut:
bmp &BitMap // Base bitmap render
// rendering fields
sg_img C.sg_image // sokol image
scale_reduct f32 = 2.0 // scale of the cpu texture for filtering
@ -31,25 +30,24 @@ pub mut:
* Render functions
*
******************************************************************************/
fn (mut tf_skl TTF_render_Sokol) format_texture(){
fn (mut tf_skl TTF_render_Sokol) format_texture() {
tf_skl.bmp.format_texture()
}
pub
fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32){
pub fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32) {
scale_reduct := tf_skl.scale_reduct
device_dpi := tf_skl.device_dpi
font_size := in_font_size //* scale_reduct
// Formula: (font_size * device dpi) / (72dpi * em_unit)
//scale := ((1.0 * devide_dpi )/ f32(72 * tf_skl.bmp.tf.units_per_em))* font_size
// scale := ((1.0 * devide_dpi )/ f32(72 * tf_skl.bmp.tf.units_per_em))* font_size
scale := f32(font_size * device_dpi) / f32(72 * tf_skl.bmp.tf.units_per_em)
//dprintln("Scale: $scale")
// dprintln("Scale: $scale")
tf_skl.bmp.scale = scale * scale_reduct
w, h := tf_skl.bmp.get_bbox(in_txt)
tf_skl.bmp.width = int(w)
tf_skl.bmp.height = int((h+8))
tf_skl.bmp.height = int((h + 8))
sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp
// RAM buffer
@ -57,7 +55,7 @@ fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32){
if sz > 0 {
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_size = sz
}
@ -66,37 +64,36 @@ fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32){
// draw the text
mut y_base := int((tf_skl.bmp.tf.y_max - tf_skl.bmp.tf.y_min) * tf_skl.bmp.scale)
tf_skl.bmp.set_pos(0,y_base)
tf_skl.bmp.set_pos(0, y_base)
tf_skl.bmp.clear()
tf_skl.bmp.draw_text(in_txt)
tf_skl.format_texture()
}
pub
fn (mut tf_skl TTF_render_Sokol) create_text_block(in_txt string, in_w int, in_h int, in_font_size f32){
pub 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
device_dpi := tf_skl.device_dpi
font_size := in_font_size //* scale_reduct
// Formula: (font_size * device dpi) / (72dpi * em_unit)
//scale := ((1.0 * devide_dpi )/ f32(72 * tf_skl.bmp.tf.units_per_em))* font_size
// scale := ((1.0 * devide_dpi )/ f32(72 * tf_skl.bmp.tf.units_per_em))* font_size
scale := f32(font_size * device_dpi) / f32(72 * tf_skl.bmp.tf.units_per_em)
//dprintln("Scale: $scale")
// dprintln("Scale: $scale")
tf_skl.bmp.scale = scale * scale_reduct
w := in_w
h := in_h
tf_skl.bmp.width = int(w * scale_reduct + 0.5)
tf_skl.bmp.height = int((h+2) * scale_reduct + 0.5)
tf_skl.bmp.height = int((h + 2) * scale_reduct + 0.5)
sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp
//if true { return }
// if true { return }
// RAM buffer
if sz > tf_skl.bmp.buf_size {
if sz > 0 {
free(tf_skl.bmp.buf)
}
dprintln("Alloc: $sz bytes")
dprintln('Alloc: $sz bytes')
tf_skl.bmp.buf = malloc(sz)
tf_skl.bmp.buf_size = sz
}
@ -105,19 +102,19 @@ fn (mut tf_skl TTF_render_Sokol) create_text_block(in_txt string, in_w int, in_h
// draw the text
mut y_base := int((tf_skl.bmp.tf.y_max - tf_skl.bmp.tf.y_min) * tf_skl.bmp.scale)
tf_skl.bmp.set_pos(0,y_base)
tf_skl.bmp.set_pos(0, y_base)
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()
}
/******************************************************************************
*
* Sokol Render functions
*
******************************************************************************/
pub
fn (mut tf_skl TTF_render_Sokol) create_texture(){
pub fn (mut tf_skl TTF_render_Sokol) create_texture() {
w := tf_skl.bmp.width
h := tf_skl.bmp.height
sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp
@ -127,7 +124,7 @@ fn (mut tf_skl TTF_render_Sokol) create_texture(){
num_mipmaps: 0
min_filter: .linear
mag_filter: .linear
//usage: .dynamic
// usage: .dynamic
wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge
label: &byte(0)
@ -140,31 +137,28 @@ fn (mut tf_skl TTF_render_Sokol) create_texture(){
}
simg := C.sg_make_image(&img_desc)
//free(tf_skl.bmp.buf) // DONT FREE IF Dynamic
// free(tf_skl.bmp.buf) // DONT FREE IF Dynamic
tf_skl.sg_img = simg
}
pub
fn (tf_skl TTF_render_Sokol) destroy_texture(){
pub fn (tf_skl TTF_render_Sokol) destroy_texture() {
C.sg_destroy_image(tf_skl.sg_img)
}
// Use only if usage: .dynamic
pub
fn (mut tf_skl TTF_render_Sokol) update_text_texture(){
pub fn (mut tf_skl TTF_render_Sokol) update_text_texture() {
sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp
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{
ptr: tf_skl.bmp.buf
size: sz
}
C.sg_update_image(tf_skl.sg_img, &tmp_sbc)
}
pub
fn (tf_skl TTF_render_Sokol) draw_text_bmp(ctx &gg.Context, x f32, y f32) {
//width := tf_skl.bmp.width >> 1
//height := tf_skl.bmp.height >> 1
pub fn (tf_skl TTF_render_Sokol) draw_text_bmp(ctx &gg.Context, x f32, y f32) {
// width := tf_skl.bmp.width >> 1
// height := tf_skl.bmp.height >> 1
sgl.push_matrix()
width := tf_skl.bmp.width / (tf_skl.scale_reduct)
@ -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))
sa := f32(math.sin(tf_skl.bmp.angle))
m := [
f32(ca),-sa,0,0,
sa,ca,0,0,
0,0,1,0,
x,y,0,1
f32(ca),
-sa,
0,
0,
sa,
ca,
0,
0,
0,
0,
1,
0,
x,
y,
0,
1,
]
sgl.mult_matrix(m)
//

View File

@ -1,4 +1,5 @@
module ttf
/**********************************************************************
*
* BMP render module utility functions
@ -11,8 +12,7 @@ module ttf
*
* TODO:
**********************************************************************/
pub
struct Text_block {
pub struct Text_block {
x int // x postion of the left high corner
y int // y postion of the left high corner
w int // width of the text block
@ -21,26 +21,25 @@ struct Text_block {
}
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 {
return 0
}
delta := block_w - w
//println("num spc: $num_spaces")
//println("delta: ${txt} w:$w bw:$block_w space_cw:$space_cw")
res := f32(delta)/f32(num_spaces)/f32(space_cw)
//println("res: $res")
// println("num spc: $num_spaces")
// println("delta: ${txt} w:$w bw:$block_w space_cw:$space_cw")
res := f32(delta) / f32(num_spaces) / f32(space_cw)
// println("res: $res")
return res
}
// write out a text
pub
fn (mut bmp BitMap) draw_text_block(text string, block Text_block) {
pub fn (mut bmp BitMap) draw_text_block(text string, block Text_block) {
mut x := block.x
mut y := block.y
mut y_base := int((bmp.tf.y_max - bmp.tf.y_min) * bmp.scale)
//bmp.box(x, y, x + block.w, y + block.h, u32(0xFF00_0000))
// bmp.box(x, y, x + block.w, y + block.h, u32(0xFF00_0000))
// spaces data
mut space_cw, _ := bmp.tf.get_horizontal_metrics(u16(` `))
@ -57,40 +56,40 @@ fn (mut bmp BitMap) draw_text_block(text string, block Text_block) {
for txt in text.split_into_lines() {
bmp.space_cw = old_space_cw
mut w,mut h := bmp.get_bbox(txt)
mut w, mut h := bmp.get_bbox(txt)
if w <= block.w || block.cut_lines == false {
//println("Solid block!")
// println("Solid block!")
left_offset := int((block.w - w) * offset_flag)
if bmp.justify && (f32(w) / f32(block.w)) >= bmp.justify_fill_ratio {
bmp.space_cw = old_space_cw + bmp.get_justify_space_cw(txt, w, block.w, space_cw)
}
bmp.set_pos(x + left_offset ,y + y_base)
bmp.set_pos(x + left_offset, y + y_base)
bmp.draw_text(txt)
//---- DEBUG ----
//mut txt_w , mut txt_h := bmp.draw_text(txt)
//bmp.box(x + left_offset,y+y_base - int((bmp.tf.y_min)*bmp.scale), x + txt_w + left_offset, y + y_base - int((bmp.tf.y_max) * bmp.scale), u32(0x00ff_0000) )
// mut txt_w , mut txt_h := bmp.draw_text(txt)
// bmp.box(x + left_offset,y+y_base - int((bmp.tf.y_min)*bmp.scale), x + txt_w + left_offset, y + y_base - int((bmp.tf.y_max) * bmp.scale), u32(0x00ff_0000) )
//---------------
y += y_base
} else {
//println("to cut: ${txt}")
mut txt1 := txt.split(" ")
mut c:= txt1.len
//mut done := false
// println("to cut: ${txt}")
mut txt1 := txt.split(' ')
mut c := txt1.len
// mut done := false
for c > 0 {
tmp_str := txt1[0..c].join(' ')
//println("tmp_str: ${tmp_str}")
// println("tmp_str: ${tmp_str}")
if tmp_str.len < 1 {
break
}
bmp.space_cw = old_space_cw
w,h = bmp.get_bbox(tmp_str)
w, h = bmp.get_bbox(tmp_str)
if w <= block.w {
mut left_offset := int((block.w - w) * offset_flag)
if bmp.justify && (f32(w) / f32(block.w)) >= bmp.justify_fill_ratio {
//println("cut phase!")
// println("cut phase!")
bmp.space_cw = 0.0
w,h = bmp.get_bbox(tmp_str)
w, h = bmp.get_bbox(tmp_str)
left_offset = int((block.w - w) * offset_flag)
bmp.space_cw = bmp.get_justify_space_cw(tmp_str, w, block.w, space_cw)
} else {
@ -99,16 +98,16 @@ fn (mut bmp BitMap) draw_text_block(text string, block Text_block) {
bmp.set_pos(x + left_offset, y + y_base)
bmp.draw_text(tmp_str)
//---- DEBUG ----
//txt_w , txt_h := bmp.draw_text(tmp_str)
//println("printing [${x},${y}] => '${tmp_str}' space_cw: $bmp.space_cw")
//bmp.box(x + left_offset,y + y_base - int((bmp.tf.y_min)*bmp.scale), x + txt_w + left_offset, y + y_base - int((bmp.tf.y_max) * bmp.scale), u32(0x00ff_0000) )
// txt_w , txt_h := bmp.draw_text(tmp_str)
// println("printing [${x},${y}] => '${tmp_str}' space_cw: $bmp.space_cw")
// bmp.box(x + left_offset,y + y_base - int((bmp.tf.y_min)*bmp.scale), x + txt_w + left_offset, y + y_base - int((bmp.tf.y_max) * bmp.scale), u32(0x00ff_0000) )
//---------------
y += y_base
txt1 = txt1[c..]
c= txt1.len
c = txt1.len
//---- DEBUG ----
//txt2 := txt1.join(' ')
//println("new string: ${txt2} len: ${c}")
// txt2 := txt1.join(' ')
// println("new string: ${txt2} len: ${c}")
//---------------
} else {
c--

View File

@ -1,4 +1,5 @@
module ttf
/**********************************************************************
*
* TrueTypeFont reader V implementation
@ -16,7 +17,6 @@ module ttf
**********************************************************************/
import strings
/******************************************************************************
*
* CMAP structs
@ -33,7 +33,7 @@ mut:
struct TrueTypeCmap {
mut:
format int
cache []int = []int{ len: 65536, init: -1 } // for now we allocate 2^16 charcode
cache []int = []int{len: 65536, init: -1} // for now we allocate 2^16 charcode
segments []Segment
arr []int
}
@ -43,21 +43,16 @@ mut:
* TTF_File structs
*
******************************************************************************/
pub
struct TTF_File{
pub struct TTF_File {
pub mut:
buf []byte
pos u32
length u16
scalar_type u32
search_range u16
entry_selector u16
range_shift u16
tables map[string]Offset_Table
version f32
font_revision f32
checksum_adjustment u32
@ -75,14 +70,11 @@ pub mut:
font_direction_hint i16
index_to_loc_format i16
glyph_data_format i16
font_family string
font_sub_family string
full_name string
postscript_name string
cmaps []TrueTypeCmap
ascent i16
descent i16
line_gap i16
@ -95,34 +87,30 @@ pub mut:
caret_offset i16
metric_data_format i16
num_of_long_hor_metrics u16
kern []Kern0Table
// cache
glyph_cache map[int]Glyph
}
pub
fn (mut tf TTF_File) init() {
pub fn (mut tf TTF_File) init() {
tf.read_offset_tables()
tf.read_head_table()
//dprintln(tf.get_info_string())
// dprintln(tf.get_info_string())
tf.read_name_table()
tf.read_cmap_table()
tf.read_hhea_table()
tf.read_kern_table()
tf.length = tf.glyph_count()
dprintln("Number of symbols: $tf.length")
dprintln("*****************************")
dprintln('Number of symbols: $tf.length')
dprintln('*****************************')
}
/******************************************************************************
*
* TTF_File Glyph Structs
*
******************************************************************************/
pub
struct Point {
pub struct Point {
pub mut:
x int
y int
@ -135,15 +123,14 @@ mut:
}
// type of glyph
const(
const (
g_type_simple = u16(1) // simple type
g_type_complex = u16(2) // compound type
)
pub
struct Glyph {
pub struct Glyph {
pub mut:
g_type u16 = g_type_simple
g_type u16 = ttf.g_type_simple
contour_ends []u16
number_of_contours i16
points []Point
@ -155,17 +142,15 @@ pub mut:
components []Component
}
/******************************************************************************
*
* TTF_File metrics and glyph
*
******************************************************************************/
pub
fn (mut tf TTF_File) get_horizontal_metrics(glyph_index u16) (int, int) {
assert"hmtx" in tf.tables
pub fn (mut tf TTF_File) get_horizontal_metrics(glyph_index u16) (int, int) {
assert 'hmtx' in tf.tables
old_pos := tf.pos
mut offset := tf.tables["hmtx"].offset
mut offset := tf.tables['hmtx'].offset
mut advance_width := 0
mut left_side_bearing := 0
@ -174,25 +159,26 @@ fn (mut tf TTF_File) get_horizontal_metrics(glyph_index u16) (int, int) {
tf.pos = offset
advance_width = tf.get_u16()
left_side_bearing = tf.get_i16()
//dprintln("Found h_metric aw: $advance_width lsb: $left_side_bearing")
// dprintln("Found h_metric aw: $advance_width lsb: $left_side_bearing")
} else {
// read the last entry of the hMetrics array
tf.pos = offset + (tf.num_of_long_hor_metrics - 1) * 4
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()
}
tf.pos = old_pos
return advance_width, left_side_bearing
}
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
assert "loca" in tf.tables
assert "glyf" in tf.tables
assert 'loca' in tf.tables
assert 'glyf' in tf.tables
mut old_pos := tf.pos
table := tf.tables["loca"]
table := tf.tables['loca']
mut offset := u32(0)
mut next := u32(0)
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)
return 0
}
//dprintln("Offset for glyph index $index is $offset")
// dprintln("Offset for glyph index $index is $offset")
tf.pos = old_pos
return offset + tf.tables['glyf'].offset
}
fn (mut tf TTF_File) glyph_count() u16{
assert "maxp" in tf.tables
fn (mut tf TTF_File) glyph_count() u16 {
assert 'maxp' in tf.tables
old_pos := tf.pos
tf.pos = tf.tables["maxp"].offset + 4
tf.pos = tf.tables['maxp'].offset + 4
count := tf.get_u16()
tf.pos = old_pos
return count
}
pub
fn (mut tf TTF_File) read_glyph_dim(index u16) (int, int, int, int) {
pub fn (mut tf TTF_File) read_glyph_dim(index u16) (int, int, int, int) {
offset := tf.get_glyph_offset(index)
//dprintln("offset: $offset")
if offset == 0 || offset >= tf.tables["glyf"].offset + tf.tables["glyf"].length {
dprintln("No glyph found!")
// dprintln("offset: $offset")
if offset == 0 || offset >= tf.tables['glyf'].offset + tf.tables['glyf'].length {
dprintln('No glyph found!')
return 0, 0, 0, 0
}
assert offset >= tf.tables["glyf"].offset
assert offset < tf.tables["glyf"].offset + tf.tables["glyf"].length
assert offset >= tf.tables['glyf'].offset
assert offset < tf.tables['glyf'].offset + tf.tables['glyf'].length
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()
y_min := tf.get_fword()
x_max := tf.get_fword()
@ -248,29 +233,29 @@ fn (mut tf TTF_File) read_glyph_dim(index u16) (int, int, int, int) {
return x_min, x_max, y_min, y_max
}
pub
fn (mut tf TTF_File) read_glyph(index u16) Glyph {
index_int := int(index) //index.str()
if index_int in tf.glyph_cache{
//dprintln("Found glyp: ${index}")
pub fn (mut tf TTF_File) read_glyph(index u16) Glyph {
index_int := int(index) // index.str()
if index_int in tf.glyph_cache {
// dprintln("Found glyp: ${index}")
return tf.glyph_cache[index_int]
}
//dprintln("Create glyp: ${index}")
// dprintln("Create glyp: ${index}")
offset := tf.get_glyph_offset(index)
//dprintln("offset: $offset")
if offset == 0 || offset >= tf.tables["glyf"].offset + tf.tables["glyf"].length {
dprintln("No glyph found!")
// dprintln("offset: $offset")
if offset == 0 || offset >= tf.tables['glyf'].offset + tf.tables['glyf'].length {
dprintln('No glyph found!')
return Glyph{}
}
assert offset >= tf.tables["glyf"].offset
assert offset < tf.tables["glyf"].offset + tf.tables["glyf"].length
assert offset >= tf.tables['glyf'].offset
assert offset < tf.tables['glyf'].offset + tf.tables['glyf'].length
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
mut tmp_glyph := Glyph{
number_of_contours : tf.get_i16()
@ -288,15 +273,15 @@ fn (mut tf TTF_File) read_glyph(index u16) Glyph {
tmp_glyph.x_max = tf.get_fword()
tmp_glyph.y_max = tf.get_fword()
//dprintln("file seek after read_glyph: $tf.pos")
// dprintln("file seek after read_glyph: $tf.pos")
assert tmp_glyph.number_of_contours >= -1
if tmp_glyph.number_of_contours == -1 {
//dprintln("read_compound_glyph")
// dprintln("read_compound_glyph")
tf.read_compound_glyph(mut tmp_glyph)
} else {
//dprintln("read_simple_glyph")
// dprintln("read_simple_glyph")
tf.read_simple_glyph(mut tmp_glyph)
}
@ -304,7 +289,7 @@ fn (mut tf TTF_File) read_glyph(index u16) Glyph {
return tmp_glyph
}
const(
const (
tfk_on_curve = 1
tfk_x_is_byte = 2
tfk_y_is_byte = 4
@ -313,12 +298,12 @@ const(
tfk_y_delta = 32
)
fn (mut tf TTF_File) read_simple_glyph(mut in_glyph Glyph){
fn (mut tf TTF_File) read_simple_glyph(mut in_glyph Glyph) {
if in_glyph.number_of_contours == 0 {
return
}
for _ in 0..in_glyph.number_of_contours {
for _ in 0 .. in_glyph.number_of_contours {
in_glyph.contour_ends << tf.get_u16()
}
@ -341,10 +326,9 @@ fn (mut tf TTF_File) read_simple_glyph(mut in_glyph Glyph){
in_glyph.points << Point{
x: 0
y: 0
on_curve: (flag & tfk_on_curve) > 0
on_curve: (flag & ttf.tfk_on_curve) > 0
}
if (flag & tfk_repeat) > 0 {
if (flag & ttf.tfk_repeat) > 0 {
mut repeat_count := tf.get_u8()
assert repeat_count > 0
i += repeat_count
@ -353,7 +337,7 @@ fn (mut tf TTF_File) read_simple_glyph(mut in_glyph Glyph){
in_glyph.points << Point{
x: 0
y: 0
on_curve: (flag & tfk_on_curve) > 0
on_curve: (flag & ttf.tfk_on_curve) > 0
}
repeat_count--
}
@ -363,39 +347,39 @@ fn (mut tf TTF_File) read_simple_glyph(mut in_glyph Glyph){
// read coords x
mut value := 0
for i_x in 0..num_points {
for i_x in 0 .. num_points {
flag_x := flags[i_x]
if (flag_x & tfk_x_is_byte) > 0 {
if (flag_x & tfk_x_delta) > 0 {
if (flag_x & ttf.tfk_x_is_byte) > 0 {
if (flag_x & ttf.tfk_x_delta) > 0 {
value += tf.get_u8()
} else {
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()
} else {
// value is unchanged
}
//dprintln("$i_x x: $value")
// dprintln("$i_x x: $value")
in_glyph.points[i_x].x = value
}
// read coords y
value = 0
for i_y in 0..num_points {
for i_y in 0 .. num_points {
flag_y := flags[i_y]
if (flag_y & tfk_y_is_byte) > 0 {
if (flag_y & tfk_y_delta) > 0 {
if (flag_y & ttf.tfk_y_is_byte) > 0 {
if (flag_y & ttf.tfk_y_delta) > 0 {
value += tf.get_u8()
} else {
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()
} else {
// value is unchanged
}
//dprintln("$i_y y: $value")
// dprintln("$i_y y: $value")
in_glyph.points[i_y].y = value
}
@ -403,7 +387,7 @@ fn (mut tf TTF_File) read_simple_glyph(mut in_glyph Glyph){
in_glyph.valid_glyph = true
}
const(
const (
tfkc_arg_1_and_2_are_words = 1
tfkc_args_are_xy_values = 2
tfkc_round_xy_to_grid = 4
@ -425,11 +409,11 @@ mut:
matrix []f32 = [f32(1.0), 0, 0, 1.0, 0, 0]
}
fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph){
in_glyph.g_type = g_type_complex
fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph) {
in_glyph.g_type = ttf.g_type_complex
mut component := Component{}
mut flags := tfkc_more_components
for (flags & tfkc_more_components) > 0 {
mut flags := ttf.tfkc_more_components
for (flags & ttf.tfkc_more_components) > 0 {
mut arg1 := 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()
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()
arg2 = tf.get_i16()
} else {
@ -445,7 +429,7 @@ fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph){
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[5] = arg2
} else {
@ -453,28 +437,27 @@ fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph){
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[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[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[1] = tf.get_2dot14()
component.matrix[2] = tf.get_2dot14()
component.matrix[3] = tf.get_2dot14()
}
//dprintln("Read component glyph index ${component.glyph_index}")
//dprintln("Transform: ${component.matrix}")
// dprintln("Read component glyph index ${component.glyph_index}")
// dprintln("Transform: ${component.matrix}")
old_pos := tf.pos
simple_glyph := tf.read_glyph(component.glyph_index)
if simple_glyph.valid_glyph {
point_offset := in_glyph.points.len
for i in 0..simple_glyph.contour_ends.len {
for i in 0 .. simple_glyph.contour_ends.len {
in_glyph.contour_ends << u16(simple_glyph.contour_ends[i] + point_offset)
}
@ -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)
if (flags & tfkc_we_have_instructions) > 0 {
if (flags & ttf.tfkc_we_have_instructions) > 0 {
tf.pos = tf.get_u16() + tf.pos
}
// ok we have a valid glyph
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 {
x :=(u32(tf.buf[tf.pos]) << u32(24)) |
(u32(tf.buf[tf.pos + 1]) << u32(16)) |
(u32(tf.buf[tf.pos + 2]) << u32(8)) |
u32(tf.buf[tf.pos + 3])
x := (u32(tf.buf[tf.pos]) << u32(24)) | (u32(tf.buf[tf.pos +
1]) << u32(16)) | (u32(tf.buf[tf.pos + 2]) << u32(8)) | u32(tf.buf[tf.pos + 3])
tf.pos += 4
return x
}
@ -560,16 +540,16 @@ fn (mut tf TTF_File) get_fixed() f32 {
fn (mut tf TTF_File) get_string(length int) string {
tmp_pos := u64(tf.pos)
tf.pos += u32(length)
return unsafe{ tos(byteptr(u64(tf.buf.data)+tmp_pos), length) }
return unsafe { tos(byteptr(u64(tf.buf.data) + tmp_pos), length) }
}
fn (mut tf TTF_File) get_unicode_string(length int) string {
mut tmp_txt := strings.new_builder(length)
mut real_len := 0
for _ in 0..(length>>1) {
for _ in 0 .. (length >> 1) {
c := tf.get_u16()
c_len := ((0xe5000000>>((c>>3) & 0x1e)) & 3) + 1
c_len := ((0xe5000000 >> ((c >> 3) & 0x1e)) & 3) + 1
real_len += c_len
if c_len == 1 {
tmp_txt.write_b(byte(c & 0xff))
@ -577,11 +557,11 @@ fn (mut tf TTF_File) get_unicode_string(length int) string {
tmp_txt.write_b(byte((c >> 8) & 0xff))
tmp_txt.write_b(byte(c & 0xff))
}
//dprintln("c: ${c:c}|${ byte(c &0xff) :c} c_len: ${c_len} str_len: ${real_len} in_len: ${length}")
// dprintln("c: ${c:c}|${ byte(c &0xff) :c} c_len: ${c_len} str_len: ${real_len} in_len: ${length}")
}
tf.pos += u32(real_len)
res_txt := tmp_txt.str()
//dprintln("get_unicode_string: ${res_txt}")
// dprintln("get_unicode_string: ${res_txt}")
return res_txt
}
@ -597,7 +577,7 @@ fn (mut tf TTF_File) calc_checksum(offset u32, length u32) u32 {
mut sum := u64(0)
mut nlongs := int((length + 3) >> 2)
tf.pos = offset
//dprintln("offs: $offset nlongs: $nlongs")
// dprintln("offs: $offset nlongs: $nlongs")
for nlongs > 0 {
sum = sum + u64(tf.get_u32())
nlongs--
@ -619,21 +599,21 @@ mut:
}
fn (mut tf TTF_File) read_offset_tables() {
dprintln("*** READ TABLES OFFSET ***")
dprintln('*** READ TABLES OFFSET ***')
tf.pos = 0
tf.scalar_type = tf.get_u32()
num_tables := tf.get_u16()
tf.search_range = tf.get_u16()
tf.entry_selector= tf.get_u16()
tf.entry_selector = tf.get_u16()
tf.range_shift = tf.get_u16()
dprintln("scalar_type : [0x$tf.scalar_type.hex()]")
dprintln("num tables : [$num_tables]")
dprintln("search_range : [0x$tf.search_range.hex()]")
dprintln("entry_selector: [0x$tf.entry_selector.hex()]")
dprintln("range_shift : [0x$tf.range_shift.hex()]")
dprintln('scalar_type : [0x$tf.scalar_type.hex()]')
dprintln('num tables : [$num_tables]')
dprintln('search_range : [0x$tf.search_range.hex()]')
dprintln('entry_selector: [0x$tf.entry_selector.hex()]')
dprintln('range_shift : [0x$tf.range_shift.hex()]')
mut i:= 0
mut i := 0
for i < num_tables {
tag := tf.get_string(4)
tf.tables[tag] = {
@ -641,15 +621,15 @@ fn (mut tf TTF_File) read_offset_tables() {
offset: tf.get_u32()
length: tf.get_u32()
}
dprintln("Table: [$tag]")
//dprintln("${tf.tables[tag]}")
dprintln('Table: [$tag]')
// dprintln("${tf.tables[tag]}")
if tag != 'head' {
assert tf.calc_checksum(tf.tables[tag].offset, tf.tables[tag].length) == tf.tables[tag].checksum
}
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() {
dprintln("*** READ HEAD TABLE ***")
tf.pos = tf.tables["head"].offset
dprintln("Offset: $tf.pos")
dprintln('*** READ HEAD TABLE ***')
tf.pos = tf.tables['head'].offset
dprintln('Offset: $tf.pos')
tf.version = tf.get_fixed()
tf.font_revision = tf.get_fixed()
@ -688,20 +668,22 @@ fn (mut tf TTF_File) read_head_table() {
*
******************************************************************************/
fn (mut tf TTF_File) read_name_table() {
dprintln("*** READ NAME TABLE ***")
assert "name" in tf.tables
table_offset := tf.tables["name"].offset
tf.pos = tf.tables["name"].offset
dprintln('*** READ NAME TABLE ***')
assert 'name' in tf.tables
table_offset := tf.tables['name'].offset
tf.pos = tf.tables['name'].offset
format := tf.get_u16() // must be 0
assert format == 0
count := tf.get_u16()
string_offset := tf.get_u16()
for _ in 0..count {
for _ in 0 .. count {
platform_id := tf.get_u16()
/*platform_specific_id :=*/ tf.get_u16()
/*language_id :=*/ tf.get_u16()
// platform_specific_id :=
tf.get_u16()
// language_id :=
tf.get_u16()
name_id := tf.get_u16()
length := tf.get_u16()
offset := tf.get_u16()
@ -709,28 +691,20 @@ fn (mut tf TTF_File) read_name_table() {
old_pos := tf.pos
tf.pos = table_offset + string_offset + offset
mut name := ""
mut name := ''
if platform_id == 0 || platform_id == 3 {
name = tf.get_unicode_string(length)
} else {
name = tf.get_string(length)
}
//dprintln("Name [${platform_id} / ${platform_specific_id}] id:[$name_id] language:[$language_id] [$name]")
// dprintln("Name [${platform_id} / ${platform_specific_id}] id:[$name_id] language:[$language_id] [$name]")
tf.pos = old_pos
match name_id {
1 {
tf.font_family = name
}
2 {
tf.font_sub_family = name
}
4 {
tf.full_name = name
}
6 {
tf.postscript_name = name
}
1 { tf.font_family = name }
2 { tf.font_sub_family = name }
4 { tf.full_name = name }
6 { tf.postscript_name = name }
else {}
}
}
@ -742,9 +716,9 @@ fn (mut tf TTF_File) read_name_table() {
*
******************************************************************************/
fn (mut tf TTF_File) read_cmap_table() {
dprintln("*** READ CMAP TABLE ***")
assert "cmap" in tf.tables
table_offset := tf.tables["cmap"].offset
dprintln('*** READ CMAP TABLE ***')
assert 'cmap' in tf.tables
table_offset := tf.tables['cmap'].offset
tf.pos = table_offset
version := tf.get_u16() // must be 0
@ -753,7 +727,7 @@ fn (mut tf TTF_File) read_cmap_table() {
// tables must be sorted by platform id and then platform specific
// encoding.
for _ in 0..number_sub_tables {
for _ in 0 .. number_sub_tables {
// platforms are:
// 0 - Unicode -- use specific id 6 for full coverage. 0/4 common.
// 1 - Macintosh (Discouraged)
@ -762,7 +736,7 @@ fn (mut tf TTF_File) read_cmap_table() {
platform_id := tf.get_u16()
platform_specific_id := tf.get_u16()
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 {
tf.read_cmap(table_offset + offset)
}
@ -776,14 +750,14 @@ fn (mut tf TTF_File) read_cmap(offset u32) {
length := 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 {
dprintln(" Cmap 0 Init...")
dprintln(' Cmap 0 Init...')
mut cmap := TrueTypeCmap{}
cmap.init_0(mut tf)
tf.cmaps << cmap
} else if format == 4 {
dprintln(" Cmap 4 Init...")
dprintln(' Cmap 4 Init...')
mut cmap := TrueTypeCmap{}
cmap.init_4(mut tf)
tf.cmaps << cmap
@ -797,15 +771,15 @@ fn (mut tf TTF_File) read_cmap(offset u32) {
* CMAPS 0/4
*
******************************************************************************/
fn (mut tf TTF_File) map_code(char_code int) u16{
fn (mut tf TTF_File) map_code(char_code int) u16 {
mut index := 0
for i in 0..tf.cmaps.len {
for i in 0 .. tf.cmaps.len {
mut cmap := tf.cmaps[i]
if cmap.format == 0 {
//dprintln("format 0")
// dprintln("format 0")
index = cmap.map_0(char_code)
} else if cmap.format == 4 {
//dprintln("format 4")
// dprintln("format 4")
index = cmap.map_4(char_code, mut tf)
}
}
@ -814,16 +788,16 @@ fn (mut tf TTF_File) map_code(char_code int) u16{
fn (mut tm TrueTypeCmap) init_0(mut tf TTF_File) {
tm.format = 0
for i in 0..256 {
for i in 0 .. 256 {
glyph_index := tf.get_u8()
dprintln(" Glyph[$i] = %glyph_index")
dprintln(' Glyph[$i] = %glyph_index')
tm.arr << glyph_index
}
}
fn (mut tm TrueTypeCmap) map_0(char_code int) int {
if char_code >= 0 && char_code <= 255 {
//dprintln("charCode $char_code maps to ${tm.arr[char_code]}")
// dprintln("charCode $char_code maps to ${tm.arr[char_code]}")
return tm.arr[char_code]
}
return 0
@ -834,13 +808,15 @@ fn (mut tm TrueTypeCmap) init_4(mut tf TTF_File) {
// 2x segcount
seg_count := tf.get_u16() >> 1
/*search_range :=*/ tf.get_u16()
/*entry_selector :=*/ tf.get_u16()
/*range_shift :=*/ tf.get_u16()
// search_range :=
tf.get_u16()
// entry_selector :=
tf.get_u16()
// range_shift :=
tf.get_u16()
// Ending character code for each segment, last is 0xffff
for _ in 0..seg_count {
for _ in 0 .. seg_count {
tm.segments << Segment{0, 0, tf.get_u16(), 0}
}
@ -848,17 +824,17 @@ fn (mut tm TrueTypeCmap) init_4(mut tf TTF_File) {
tf.get_u16()
// starting character code for each segment
for i in 0..seg_count {
for i in 0 .. seg_count {
tm.segments[i].start_code = tf.get_u16()
}
// Delta for all character codes in segment
for i in 0..seg_count {
for i in 0 .. seg_count {
tm.segments[i].id_delta = tf.get_u16()
}
// offset in bytes to glyph indexArray, or 0
for i in 0..seg_count {
for i in 0 .. seg_count {
ro := u32(tf.get_u16())
if ro != 0 {
tm.segments[i].id_range_offset = tf.pos - 2 + ro
@ -866,26 +842,27 @@ fn (mut tm TrueTypeCmap) init_4(mut tf TTF_File) {
tm.segments[i].id_range_offset = 0
}
}
/*
/*
// DEBUG LOG
for i in 0..seg_count {
seg := tm.segments[i]
dprintln(" segments[$i] = $seg.start_code $seg.end_code $seg.id_delta $seg.id_range_offset")
}
*/
*/
}
fn (mut tm TrueTypeCmap) map_4(char_code int, mut tf TTF_File) int {
//dprintln("HERE map_4 for char [$char_code]")
// dprintln("HERE map_4 for char [$char_code]")
old_pos := tf.pos
if tm.cache[char_code] == -1 {
//dprintln("Not found, search for it!")
// dprintln("Not found, search for it!")
mut found := false
for segment in tm.segments {
if segment.start_code <= char_code && segment.end_code >= char_code {
mut index := (segment.id_delta + char_code) & 0xffff
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
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() {
dprintln("*** READ HHEA TABLE ***")
assert "hhea" in tf.tables
table_offset := tf.tables["hhea"].offset
dprintln('*** READ HHEA TABLE ***')
assert 'hhea' in tf.tables
table_offset := tf.tables['hhea'].offset
tf.pos = table_offset
/*version :=*/ tf.get_fixed() // 0x00010000
// version :=
tf.get_fixed() // 0x00010000
tf.ascent = tf.get_fword()
tf.descent = tf.get_fword()
@ -957,14 +935,14 @@ fn (mut kt Kern0Table) get(glyph_index int) (int, int) {
if kt.old_index >= 0 {
ch := ((u32(kt.old_index & 0xFFFF) << 16) | u32(glyph_index & 0xFFFF))
//dprintln("kern_get: $ch")
// dprintln("kern_get: $ch")
if ch in kt.kmap {
x = int(kt.kmap[ch])
}
}
kt.old_index = glyph_index
if kt.swap {
return 0 , x
return 0, x
}
return x, 0
}
@ -975,7 +953,7 @@ fn (mut tf TTF_File) create_kern_table0(vertical bool, cross bool) Kern0Table {
search_range := tf.get_u16()
entry_selector := 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{
swap: (vertical && !cross) || (!vertical && cross)
@ -983,61 +961,61 @@ fn (mut tf TTF_File) create_kern_table0(vertical bool, cross bool) Kern0Table {
n_pairs: n_pairs
}
for _ in 0..n_pairs {
for _ in 0 .. n_pairs {
left := tf.get_u16()
right := tf.get_u16()
value := tf.get_fword()
tmp_index := (u32(left) << 16) | u32(right)
kt0.kmap[tmp_index] = value
//dprintln("index: ${tmp_index.hex()} val: ${value.hex()}")
// dprintln("index: ${tmp_index.hex()} val: ${value.hex()}")
}
kt0.old_index = -1
return kt0
}
fn (mut tf TTF_File) read_kern_table() {
dprintln("*** READ KERN TABLE ***")
if !("kern" in tf.tables){
dprintln('*** READ KERN TABLE ***')
if !('kern' in tf.tables) {
return
}
table_offset := tf.tables["kern"].offset
table_offset := tf.tables['kern'].offset
tf.pos = table_offset
version := tf.get_u16() // must be 0
assert version == 0 // must be 0
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
length := tf.get_u16()
coverage := tf.get_u16()
format := coverage >> 8
cross := coverage & 4
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 {
dprintln("kern format: 0")
dprintln('kern format: 0')
kern := tf.create_kern_table0(vertical, cross != 0)
tf.kern << kern
} else {
dprintln("Unknown format -- skip")
dprintln('Unknown format -- skip')
tf.pos = tf.pos + length
}
}
}
fn (mut tf TTF_File) reset_kern() {
for i in 0..tf.kern.len {
for i in 0 .. tf.kern.len {
tf.kern[i].reset()
}
}
fn (mut tf TTF_File) next_kern(glyph_index int) (int, int){
fn (mut tf TTF_File) next_kern(glyph_index int) (int, int) {
mut x := 0
mut y := 0
for i in 0..tf.kern.len {
for i in 0 .. tf.kern.len {
tmp_x, tmp_y := tf.kern[i].get(glyph_index)
x = x + tmp_x
y = y + tmp_y
@ -1045,29 +1023,27 @@ fn (mut tf TTF_File) next_kern(glyph_index int) (int, int){
return x, y
}
/******************************************************************************
*
* TTF_File Utility
*
******************************************************************************/
pub
fn (tf TTF_File) get_info_string() string{
txt := "----- Font Info -----
pub fn (tf TTF_File) get_info_string() string {
txt := '----- Font Info -----
font_family : $tf.font_family
font_sub_family : $tf.font_sub_family
full_name : $tf.full_name
postscript_name : $tf.postscript_name
version : $tf.version
font_revision : $tf.font_revision
magic_number : ${tf.magic_number.hex()}
flags : ${tf.flags.hex()}
created unixTS : ${tf.created}
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}]
mac_style : ${tf.mac_style}
magic_number : $tf.magic_number.hex()
flags : $tf.flags.hex()
created unixTS : $tf.created
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]
mac_style : $tf.mac_style
-----------------------
"
'
return txt
}
@ -1076,24 +1052,34 @@ mac_style : ${tf.mac_style}
* TTF_File test
*
******************************************************************************/
fn tst(){
fn tst() {
mut tf := TTF_File{}
tf.buf = [
byte(0xFF), // 8 bit
0xF1, 0xF2, // 16 bit
0x81, 0x23, 0x45, 0x67, // 32 bit
0x12, 0x34, 0x12, 0x34, // get_2dot14 16 bit
0x12, 0x34, 0x12, 0x34 // get_fixed 32 bit int
byte(0xFF), /* 8 bit */
0xF1,
0xF2, /* 16 bit */
0x81,
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_u16().hex() == "f1f2"
assert tf.get_u32().hex() == "81234567"
assert tf.get_u8().hex() == 'ff'
assert tf.get_u16().hex() == 'f1f2'
assert tf.get_u32().hex() == '81234567'
dprintln("buf len: ${tf.buf.len}")
//dprintln( tf.get_u8().hex() )
//dprintln( tf.get_u16().hex() )
//dprintln( tf.get_u32().hex() )
//dprintln( tf.get_2dot14() )
//dprintln( tf.get_fixed() )
dprintln('buf len: $tf.buf.len')
// dprintln( tf.get_u8().hex() )
// dprintln( tf.get_u16().hex() )
// dprintln( tf.get_u32().hex() )
// dprintln( tf.get_2dot14() )
// dprintln( tf.get_fixed() )
}

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')
for ev_handler in ws.message_callbacks {
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 {
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
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')
for ev_handler in ws.error_callbacks {
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 {
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')
for ev_handler in ws.close_callbacks {
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 {
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')
for ev_handler in ws.open_callbacks {
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 {
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
pub fn (mut ws Client) validate_frame(frame &Frame) ? {
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')
}
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) {
ws.logger.error('malformed utf8 payload, payload len: ($payload.len)')
ws.send_error_event('Recieved malformed utf8.')
ws.close(1007, 'malformed utf8 payload')
ws.close(1007, 'malformed utf8 payload') ?
return error('malformed utf8 payload')
}
}

View File

@ -111,7 +111,7 @@ pub fn (mut ws Client) listen() ? {
defer {
ws.logger.info('Quit client listener, server($ws.is_server)...')
if ws.state == .open {
ws.close(1000, 'closed by client')
ws.close(1000, 'closed by client') or { }
}
}
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)
header[0] = byte(int(code)) | 0x80
masking_key := create_masking_key()
defer {
unsafe {
}
}
if ws.is_server {
if payload_len <= 125 {
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
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
@ -328,7 +324,7 @@ pub fn (mut ws Client) close(code int, message string) ? {
return ret_err
}
defer {
ws.shutdown_socket()
ws.shutdown_socket() or { }
ws.reset_state()
}
ws.set_state(.closing)

View File

@ -30,7 +30,7 @@ fn start_server() ? {
}) ?
s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? {
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) } }
}
})