1476 lines
41 KiB
Markdown
1476 lines
41 KiB
Markdown
|
|
# BASIC INSTRUCTIONS
|
|
|
|
IMPORTANT: USE THIS PAGE AS THE ABSOLUTE AUTHORITY ON ALL INSTRUCTIONS IN RELATION TO HEROSCRIPT AND VLANG
|
|
|
|
## instructions for code generation
|
|
|
|
> when I generate code, the following instructions can never be overruled they are the basics
|
|
|
|
- do not try to fix files which end with _.v because these are generated files
|
|
|
|
## instruction for vlang scripts
|
|
|
|
when I generate vlang scripts I will always use .vsh extension and use following as first line:
|
|
|
|
```
|
|
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
|
```
|
|
|
|
- a .vsh is a v shell script and can be executed as is, no need to use v ...
|
|
- in .vsh file there is no need for a main() function
|
|
- these scripts can be used for examples or instruction scripts e.g. an installs script
|
|
|
|
## executing vlang scripts
|
|
|
|
As AI agent I should also execute .v or .vsh scripts with vrun
|
|
|
|
```bash
|
|
vrun ~/code/github/incubaid/herolib/examples/biztools/bizmodel.vsh
|
|
```
|
|
|
|
## executing test scripts
|
|
|
|
instruct user to test as follows (vtest is an alias which gets installed when herolib gets installed), can be done for a dir and for a file
|
|
|
|
```bash
|
|
vtest ~/code/github/incubaid/herolib/lib/osal/package_test.v
|
|
```
|
|
|
|
- use ~ so it works over all machines
|
|
- don't use 'v test', we have vtest as alternative
|
|
|
|
## module imports
|
|
|
|
- in v all files in a folder are part of the same module, no need to import then, this is important difference in v compared to other languages.
|
|
|
|
## usage of /@[params]
|
|
|
|
- this is the best way how to pass optional parameters to functions in V
|
|
|
|
```
|
|
|
|
/@[params]
|
|
pub struct MyArgs {
|
|
pub mut:
|
|
name string
|
|
passphrase string
|
|
}
|
|
|
|
pub fn my_function(args MyArgs) {
|
|
// Use args.name and args.passphrase
|
|
}
|
|
|
|
//it get called as follows
|
|
|
|
my_function(name:"my_key", passphrase:"my_passphrase")
|
|
|
|
//IMPORTANT NO NEED TO INITIALIZE THE MYARGS INSIDE
|
|
|
|
```
|
|
|
|
# Getting the Current Script's Path in Herolib/V Shell
|
|
|
|
can be used in any .v or .vsh script, easy to find content close to the script itself.
|
|
|
|
```v
|
|
#!/usr/bin/env vsh
|
|
|
|
const script_path = os.dir(/@FILE) + '/scripts'
|
|
echo "Current scripts directory: ${script_directory}"
|
|
|
|
```
|
|
|
|
```
|
|
|
|
File: /Users/despiegk/code/github/incubaid/herolib/aiprompts/herolib_core/core_heroscript_basics.md
|
|
```md
|
|
# HeroScript: Vlang Integration
|
|
|
|
## HeroScript Structure
|
|
|
|
HeroScript is a concise scripting language with the following structure:
|
|
|
|
```heroscript
|
|
!!actor.action_name
|
|
param1: 'value1'
|
|
param2: 'value with spaces'
|
|
multiline_description: '
|
|
This is a multiline description.
|
|
It can span multiple lines.
|
|
'
|
|
arg1 arg2 // Arguments without keys
|
|
```
|
|
|
|
Key characteristics:
|
|
|
|
- **Actions**: Start with `!!`, followed by `actor.action_name` (e.g., `!!mailclient.configure`).
|
|
- **Parameters**: Defined as `key:value`. Values can be quoted for spaces.
|
|
- **Multiline Support**: Parameters like `description` can span multiple lines.
|
|
- **Arguments**: Values without keys (e.g., `arg1`).
|
|
|
|
## Processing HeroScript in Vlang
|
|
|
|
HeroScript can be parsed into a `playbook.PlayBook` object, allowing structured access to actions and their parameters, this is used in most of the herolib modules, it allows configuration or actions in a structured way.
|
|
|
|
```v
|
|
import incubaid.herolib.core.playbook { PlayBook }
|
|
import incubaid.herolib.ui.console
|
|
|
|
pub fn play(mut plbook PlayBook) ! {
|
|
|
|
if plbook.exists_once(filter: 'docusaurus.define') {
|
|
mut action := plbook.get(filter: 'docusaurus.define')!
|
|
mut p := action.params
|
|
//example how we get parameters from the action see aiprompts/herolib_core/core_params.md for more details
|
|
path_build := p.get_default('path_build', '')!
|
|
path_publish := p.get_default('path_publish', '')!
|
|
reset := p.get_default_false('reset')
|
|
use_doctree := p.get_default_false('use_doctree')
|
|
}
|
|
|
|
// Process 'docusaurus.add' actions to configure individual Docusaurus sites
|
|
actions := plbook.find(filter: 'docusaurus.add')!
|
|
for action in actions {
|
|
mut p := action.params
|
|
//do more processing here
|
|
}
|
|
}
|
|
```
|
|
|
|
For detailed information on parameter retrieval methods (e.g., `p.get()`, `p.get_int()`, `p.get_default_true()`), refer to `aiprompts/herolib_core/core_params.md`.
|
|
|
|
# PlayBook, process heroscripts
|
|
|
|
HeroScript can be parsed into a `playbook.PlayBook` object, allowing structured access to actions and their parameters.
|
|
|
|
```v
|
|
import incubaid.herolib.core.playbook
|
|
import incubaid.herolib.core.playcmds
|
|
|
|
// path string
|
|
// text string
|
|
// git_url string
|
|
// git_pull bool
|
|
// git_branch string
|
|
// git_reset bool
|
|
// session ?&base.Session is optional
|
|
mut plbook := playbook.new(path: "....")!
|
|
|
|
//now we run all the commands as they are pre-defined in herolib, this will execute the playbook and do all actions.
|
|
playcmds.run(mut plbook)!
|
|
|
|
```
|
|
|
|
# HTTPConnection Module
|
|
|
|
The `HTTPConnection` module provides a robust HTTP client for Vlang, supporting JSON, custom headers, retries, and caching.
|
|
|
|
## Key Features
|
|
|
|
- Type-safe JSON methods
|
|
- Custom headers
|
|
- Retry mechanism
|
|
- Caching
|
|
- URL encoding
|
|
|
|
## Basic Usage
|
|
|
|
```v
|
|
import incubaid.herolib.core.httpconnection
|
|
|
|
// Create a new HTTP connection
|
|
mut conn := httpconnection.new(
|
|
name: 'my_api_client'
|
|
url: 'https://api.example.com'
|
|
retry: 3 // Number of retries for failed requests
|
|
cache: true // Enable caching
|
|
)!
|
|
```
|
|
|
|
## Integration with Management Classes
|
|
|
|
To integrate `HTTPConnection` into a management class (e.g., `HetznerManager`), use a method to lazily initialize and return the connection:
|
|
|
|
```v
|
|
// Example: HetznerManager
|
|
pub fn (mut h HetznerManager) connection() !&httpconnection.HTTPConnection {
|
|
mut c := h.conn or {
|
|
mut c2 := httpconnection.new(
|
|
name: 'hetzner_${h.name}'
|
|
url: h.baseurl
|
|
cache: true
|
|
retry: 3
|
|
)!
|
|
c2.basic_auth(h.user, h.password)
|
|
c2
|
|
}
|
|
return c
|
|
}
|
|
```
|
|
|
|
## Examples
|
|
|
|
### GET Request with JSON Response
|
|
|
|
```v
|
|
struct User {
|
|
id int
|
|
name string
|
|
email string
|
|
}
|
|
|
|
user := conn.get_json_generic[User](
|
|
prefix: 'users/1'
|
|
)!
|
|
```
|
|
|
|
### POST Request with JSON Data
|
|
|
|
```v
|
|
struct NewUserResponse {
|
|
id int
|
|
status string
|
|
}
|
|
|
|
new_user_resp := conn.post_json_generic[NewUserResponse](
|
|
prefix: 'users'
|
|
params: {
|
|
'name': 'Jane Doe'
|
|
'email': 'jane/@example.com'
|
|
}
|
|
)!
|
|
```
|
|
|
|
### Custom Headers
|
|
|
|
Set default headers or add them per request:
|
|
|
|
```v
|
|
import net.http { Header }
|
|
|
|
// Set default header
|
|
conn.default_header = http.new_header(key: .authorization, value: 'Bearer your-token')
|
|
|
|
// Add custom header for a specific request
|
|
response := conn.get_json(
|
|
prefix: 'protected/resource'
|
|
header: http.new_header(key: .content_type, value: 'application/json')
|
|
)!
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
Methods return a `Result` type for error handling:
|
|
|
|
```v
|
|
user := conn.get_json_generic[User](
|
|
prefix: 'users/1'
|
|
) or {
|
|
println('Error fetching user: ${err}')
|
|
return
|
|
}
|
|
|
|
```
|
|
|
|
# OSAL Core Module - SYSTEM TOOLS OS - Key Capabilities (incubaid.herolib.osal.core)
|
|
|
|
```v
|
|
//example how to get started
|
|
|
|
import incubaid.herolib.osal.core as osal
|
|
|
|
job := osal.exec(cmd: 'ls /')!
|
|
```
|
|
|
|
This document describes the core functionalities of the Operating System Abstraction Layer (OSAL) module, designed for platform-independent system operations in V.
|
|
|
|
## 1. Process Execution
|
|
|
|
- **`osal.exec(cmd: Command) !Job`**: Execute a shell command.
|
|
- **Key Parameters**: `cmd` (string), `timeout` (int), `retry` (int), `work_folder` (string), `environment` (map[string]string), `stdout` (bool), `raise_error` (bool).
|
|
- **Returns**: `Job` (status, output, error, exit code).
|
|
- **`osal.execute_silent(cmd string) !string`**: Execute silently, return output.
|
|
- **`osal.execute_debug(cmd string) !string`**: Execute with debug output, return output.
|
|
- **`osal.execute_stdout(cmd string) !string`**: Execute and print output to stdout, return output.
|
|
- **`osal.execute_interactive(cmd string) !`**: Execute in an interactive shell.
|
|
- **`osal.cmd_exists(cmd string) bool`**: Check if a command exists.
|
|
|
|
## 2. Network Utilities
|
|
|
|
- **`osal.ping(args: PingArgs) !bool`**: Check host reachability.
|
|
- address string = "8.8.8.8"
|
|
- nr_ping u16 = 3 // amount of ping requests we will do
|
|
- nr_ok u16 = 3 //how many of them need to be ok
|
|
- retry u8 //how many times fo we retry above sequence, basically we ping ourselves with -c 1
|
|
**`osal.ipaddr_pub_get() !string`**: Get public IP address.
|
|
|
|
## 3. File System Operations
|
|
|
|
- **`osal.file_write(path string, text string) !`**: Write text to a file.
|
|
- **`osal.file_read(path string) !string`**: Read content from a file.
|
|
- **`osal.dir_ensure(path string) !`**: Ensure a directory exists.
|
|
- **`osal.rm(todelete string) !`**: Remove files/directories.
|
|
|
|
## 4. Environment Variables
|
|
|
|
- **`osal.env_set(args: EnvSet)`**: Set an environment variable.
|
|
- **Key Parameters**: `key` (string), `value` (string).
|
|
- **`osal.env_unset(key string)`**: Unset a specific environment variable.
|
|
- **`osal.env_unset_all()`**: Unset all environment variables.
|
|
- **`osal.env_set_all(args: EnvSetAll)`**: Set multiple environment variables.
|
|
- **Key Parameters**: `env` (map[string]string), `clear_before_set` (bool), `overwrite_if_exists` (bool).
|
|
- **`osal.env_get(key string) !string`**: Get an environment variable's value.
|
|
- **`osal.env_exists(key string) !bool`**: Check if an environment variable exists.
|
|
- **`osal.env_get_default(key string, def string) string`**: Get an environment variable or a default value.
|
|
- **`osal.load_env_file(file_path string) !`**: Load variables from a file.
|
|
|
|
## 5. Command & Profile Management
|
|
|
|
- **`osal.cmd_add(args: CmdAddArgs) !`**: Add a binary to system paths and update profiles.
|
|
- **Key Parameters**: `source` (string, required), `cmdname` (string).
|
|
- **`osal.profile_path_add_remove(args: ProfilePathAddRemoveArgs) !`**: Add/remove paths from profiles.
|
|
- **Key Parameters**: `paths2add` (string), `paths2delete` (string).
|
|
|
|
## 6. System Information & Utilities
|
|
|
|
- **`osal.processmap_get() !ProcessMap`**: Get a map of all running processes.
|
|
- **`osal.processinfo_get(pid int) !ProcessInfo`**: Get detailed information for a specific process.
|
|
- **`osal.processinfo_get_byname(name string) ![]ProcessInfo`**: Get info for processes matching a name.
|
|
- **`osal.process_exists(pid int) bool`**: Check if a process exists by PID.
|
|
- **`osal.processinfo_with_children(pid int) !ProcessMap`**: Get a process and its children.
|
|
- **`osal.processinfo_children(pid int) !ProcessMap`**: Get children of a process.
|
|
- **`osal.process_kill_recursive(args: ProcessKillArgs) !`**: Kill a process and its children.
|
|
- **Key Parameters**: `name` (string), `pid` (int).
|
|
- **`osal.whoami() !string`**: Return the current username.
|
|
- **`osal.hostname() !string`**: Get system hostname.
|
|
- **`osal.sleep(duration int)`**: Pause execution for a specified duration.
|
|
- **`osal.download(args: DownloadArgs) !pathlib.Path`**: Download a file from a URL.
|
|
- `pathlib.Path` is from `incubaid.herolib.core.pathlib`
|
|
- **Key Parameters**: `url` (string), `dest` (string), `timeout` (int), `retry` (int).
|
|
- **`osal.user_exists(username string) bool`**: Check if a user exists.
|
|
- **`osal.user_id_get(username string) !int`**: Get user ID.
|
|
- **`osal.user_add(args: UserArgs) !int`**: Add a user.
|
|
- **Key Parameters**: `name` (string).
|
|
|
|
```
|
|
|
|
## 7. Platform Information
|
|
|
|
* **`core.platform() !PlatformType`**: Identify the operating system.
|
|
* **Returns**: Platform type (osx, ubuntu, arch, etc.)
|
|
* **`core.cputype() !CPUType`**: Identify the CPU architecture.
|
|
* **Returns**: CPU type (intel, arm, etc.)
|
|
|
|
### Usage Example
|
|
|
|
```v
|
|
import incubaid.herolib.core
|
|
|
|
platform := core.platform()! // Returns .osx, .ubuntu, etc.
|
|
cpu := core.cputype()! // Returns .intel, .arm, etc.
|
|
|
|
match platform {
|
|
.osx { println('Running on macOS') }
|
|
.ubuntu { println('Running on Ubuntu') }
|
|
.arch { println('Running on Arch Linux') }
|
|
else { println('Other platform') }
|
|
}
|
|
```
|
|
|
|
# OurTime Module
|
|
|
|
The `OurTime` module in V provides flexible time handling, supporting relative and absolute time formats, Unix timestamps, and formatting utilities.
|
|
|
|
## Key Features
|
|
- Create time objects from strings or current time
|
|
- Relative time expressions (e.g., `+1h`, `-2d`)
|
|
- Absolute time formats (e.g., `YYYY-MM-DD HH:mm:ss`)
|
|
- Unix timestamp conversion
|
|
- Time formatting and warping
|
|
|
|
## Basic Usage
|
|
|
|
```v
|
|
import incubaid.herolib.data.ourtime
|
|
|
|
// Current time
|
|
mut t := ourtime.now()
|
|
|
|
// From string
|
|
t2 := ourtime.new('2022-12-05 20:14:35')!
|
|
|
|
// Get formatted string
|
|
println(t2.str()) // e.g., 2022-12-05 20:14
|
|
|
|
// Get Unix timestamp
|
|
println(t2.unix()) // e.g., 1670271275
|
|
```
|
|
|
|
## Time Formats
|
|
|
|
### Relative Time
|
|
|
|
Use `s` (seconds), `h` (hours), `d` (days), `w` (weeks), `M` (months), `Q` (quarters), `Y` (years).
|
|
|
|
```v
|
|
// Create with relative time
|
|
mut t := ourtime.new('+1w +2d -4h')!
|
|
|
|
// Warp existing time
|
|
mut t2 := ourtime.now()
|
|
t2.warp('+1h')!
|
|
```
|
|
|
|
### Absolute Time
|
|
|
|
Supports `YYYY-MM-DD HH:mm:ss`, `YYYY-MM-DD HH:mm`, `YYYY-MM-DD HH`, `YYYY-MM-DD`, `DD-MM-YYYY`.
|
|
|
|
```v
|
|
t1 := ourtime.new('2022-12-05 20:14:35')!
|
|
t2 := ourtime.new('2022-12-05')! // Time defaults to 00:00:00
|
|
```
|
|
|
|
## Methods Overview
|
|
|
|
### Creation
|
|
|
|
```v
|
|
now_time := ourtime.now()
|
|
from_string := ourtime.new('2023-01-15')!
|
|
from_epoch := ourtime.new_from_epoch(1673788800)
|
|
```
|
|
|
|
### Formatting
|
|
|
|
```v
|
|
mut t := ourtime.now()
|
|
println(t.str()) // YYYY-MM-DD HH:mm
|
|
println(t.day()) // YYYY-MM-DD
|
|
println(t.key()) // YYYY_MM_DD_HH_mm_ss
|
|
println(t.md()) // Markdown format
|
|
```
|
|
|
|
### Operations
|
|
|
|
```v
|
|
mut t := ourtime.now()
|
|
t.warp('+1h')! // Move 1 hour forward
|
|
unix_ts := t.unix()
|
|
is_empty := t.empty()
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
Time parsing methods return a `Result` type and should be handled with `!` or `or` blocks.
|
|
|
|
```v
|
|
t_valid := ourtime.new('2023-01-01')!
|
|
t_invalid := ourtime.new('bad-date') or {
|
|
println('Error: ${err}')
|
|
ourtime.now() // Fallback
|
|
}
|
|
|
|
```
|
|
|
|
# Parameter Parsing in Vlang
|
|
|
|
This document details the `paramsparser` module, essential for handling parameters in HeroScript and other contexts.
|
|
|
|
## Obtaining a `paramsparser` Instance
|
|
|
|
```v
|
|
import incubaid.herolib.data.paramsparser
|
|
|
|
// Create new params from a string
|
|
params := paramsparser.new("color:red size:'large' priority:1 enable:true")!
|
|
|
|
// Or create an empty instance and add parameters programmatically
|
|
mut params := paramsparser.new_params()
|
|
params.set("color", "red")
|
|
```
|
|
|
|
## Parameter Formats
|
|
|
|
The parser supports various input formats:
|
|
|
|
1. **Key-value pairs**: `key:value`
|
|
2. **Quoted values**: `key:'value with spaces'` (single or double quotes)
|
|
3. **Arguments without keys**: `arg1 arg2` (accessed by index)
|
|
4. **Comments**: `// this is a comment` (ignored during parsing)
|
|
|
|
Example:
|
|
|
|
```v
|
|
text := "name:'John Doe' age:30 active:true // user details"
|
|
params := paramsparser.new(text)!
|
|
```
|
|
|
|
## Parameter Retrieval Methods
|
|
|
|
The `paramsparser` module provides a comprehensive set of methods for retrieving and converting parameter values.
|
|
|
|
### Basic Retrieval
|
|
|
|
- `get(key string) !string`: Retrieves a string value by key. Returns an error if the key does not exist.
|
|
- `get_default(key string, defval string) !string`: Retrieves a string value by key, or returns `defval` if the key is not found.
|
|
- `exists(key string) bool`: Checks if a keyword argument (`key:value`) exists.
|
|
- `exists_arg(key string) bool`: Checks if an argument (value without a key) exists.
|
|
|
|
### Argument Retrieval (Positional)
|
|
|
|
- `get_arg(nr int) !string`: Retrieves an argument by its 0-based index. Returns an error if the index is out of bounds.
|
|
- `get_arg_default(nr int, defval string) !string`: Retrieves an argument by index, or returns `defval` if the index is out of bounds.
|
|
|
|
### Type-Specific Retrieval
|
|
|
|
- `get_int(key string) !int`: Converts and retrieves an integer (int32).
|
|
- `get_int_default(key string, defval int) !int`: Retrieves an integer with a default.
|
|
- `get_u32(key string) !u32`: Converts and retrieves an unsigned 32-bit integer.
|
|
- `get_u32_default(key string, defval u32) !u32`: Retrieves a u32 with a default.
|
|
- `get_u64(key string) !u64`: Converts and retrieves an unsigned 64-bit integer.
|
|
- `get_u64_default(key string, defval u64) !u64`: Retrieves a u64 with a default.
|
|
- `get_u8(key string) !u8`: Converts and retrieves an unsigned 8-bit integer.
|
|
- `get_u8_default(key string, defval u8) !u8`: Retrieves a u8 with a default.
|
|
- `get_float(key string) !f64`: Converts and retrieves a 64-bit float.
|
|
- `get_float_default(key string, defval f64) !f64`: Retrieves a float with a default.
|
|
- `get_percentage(key string) !f64`: Converts a percentage string (e.g., "80%") to a float (0.8).
|
|
- `get_percentage_default(key string, defval string) !f64`: Retrieves a percentage with a default.
|
|
|
|
### Boolean Retrieval
|
|
|
|
- `get_default_true(key string) bool`: Returns `true` if the value is empty, "1", "true", "y", or "yes". Otherwise `false`.
|
|
- `get_default_false(key string) bool`: Returns `false` if the value is empty, "0", "false", "n", or "no". Otherwise `true`.
|
|
|
|
### List Retrieval
|
|
|
|
Lists are typically comma-separated strings (e.g., `users: "john,jane,bob"`).
|
|
|
|
- `get_list(key string) ![]string`: Retrieves a list of strings.
|
|
- `get_list_default(key string, def []string) ![]string`: Retrieves a list of strings with a default.
|
|
- `get_list_int(key string) ![]int`: Retrieves a list of integers.
|
|
- `get_list_int_default(key string, def []int) []int`: Retrieves a list of integers with a default.
|
|
- `get_list_f32(key string) ![]f32`: Retrieves a list of 32-bit floats.
|
|
- `get_list_f32_default(key string, def []f32) []f32`: Retrieves a list of f32 with a default.
|
|
- `get_list_f64(key string) ![]f64`: Retrieves a list of 64-bit floats.
|
|
- `get_list_f64_default(key string, def []f64) []f64`: Retrieves a list of f64 with a default.
|
|
- `get_list_i8(key string) ![]i8`: Retrieves a list of 8-bit signed integers.
|
|
- `get_list_i8_default(key string, def []i8) []i8`: Retrieves a list of i8 with a default.
|
|
- `get_list_i16(key string) ![]i16`: Retrieves a list of 16-bit signed integers.
|
|
- `get_list_i16_default(key string, def []i16) []i16`: Retrieves a list of i16 with a default.
|
|
- `get_list_i64(key string) ![]i64`: Retrieves a list of 64-bit signed integers.
|
|
- `get_list_i64_default(key string, def []i64) []i64`: Retrieves a list of i64 with a default.
|
|
- `get_list_u16(key string) ![]u16`: Retrieves a list of 16-bit unsigned integers.
|
|
- `get_list_u16_default(key string, def []u16) []u16`: Retrieves a list of u16 with a default.
|
|
- `get_list_u32(key string) ![]u32`: Retrieves a list of 32-bit unsigned integers.
|
|
- `get_list_u32_default(key string, def []u32) []u32`: Retrieves a list of u32 with a default.
|
|
- `get_list_u64(key string) ![]u64`: Retrieves a list of 64-bit unsigned integers.
|
|
- `get_list_u64_default(key string, def []u64) []u64`: Retrieves a list of u64 with a default.
|
|
- `get_list_namefix(key string) ![]string`: Retrieves a list of strings, normalizing each item (e.g., "My Name" -> "my_name").
|
|
- `get_list_namefix_default(key string, def []string) ![]string`: Retrieves a list of name-fixed strings with a default.
|
|
|
|
### Specialized Retrieval
|
|
|
|
- `get_map() map[string]string`: Returns all parameters as a map.
|
|
- `get_path(key string) !string`: Retrieves a path string.
|
|
- `get_path_create(key string) !string`: Retrieves a path string, creating the directory if it doesn't exist.
|
|
- `get_from_hashmap(key string, defval string, hashmap map[string]string) !string`: Retrieves a value from a provided hashmap based on the parameter's value.
|
|
- `get_storagecapacity_in_bytes(key string) !u64`: Converts storage capacity strings (e.g., "10 GB", "500 MB") to bytes (u64).
|
|
- `get_storagecapacity_in_bytes_default(key string, defval u64) !u64`: Retrieves storage capacity in bytes with a default.
|
|
- `get_storagecapacity_in_gigabytes(key string) !u64`: Converts storage capacity strings to gigabytes (u64).
|
|
- `get_time(key string) !ourtime.OurTime`: Parses a time string (relative or absolute) into an `ourtime.OurTime` object.
|
|
- `get_time_default(key string, defval ourtime.OurTime) !ourtime.OurTime`: Retrieves time with a default.
|
|
- `get_time_interval(key string) !Duration`: Parses a time interval string into a `Duration` object.
|
|
- `get_timestamp(key string) !Duration`: Parses a timestamp string into a `Duration` object.
|
|
- `get_timestamp_default(key string, defval Duration) !Duration`: Retrieves a timestamp with a default.
|
|
|
|
```
|
|
|
|
# Pathlib Usage Guide
|
|
|
|
## Overview
|
|
|
|
The pathlib module provides a comprehensive interface for handling file system operations. Key features include:
|
|
|
|
- Robust path handling for files, directories, and symlinks
|
|
- Support for both absolute and relative paths
|
|
- Automatic home directory expansion (~)
|
|
- Recursive directory operations
|
|
- Path filtering and listing
|
|
- File and directory metadata access
|
|
|
|
## Basic Usage
|
|
|
|
### Importing pathlib
|
|
```v
|
|
import incubaid.herolib.core.pathlib
|
|
```
|
|
|
|
### Creating Path Objects
|
|
|
|
This will figure out if the path is a dir, file and if it exists.
|
|
|
|
```v
|
|
// Create a Path object for a file
|
|
mut file_path := pathlib.get("path/to/file.txt")
|
|
|
|
// Create a Path object for a directory
|
|
mut dir_path := pathlib.get("path/to/directory")
|
|
```
|
|
|
|
if you know in advance if you expect a dir or file its better to use `pathlib.get_dir(path:...,create:true)` or `pathlib.get_file(path:...,create:true)`.
|
|
|
|
### Basic Path Operations
|
|
|
|
```v
|
|
// Get absolute path
|
|
abs_path := file_path.absolute()
|
|
|
|
// Get real path (resolves symlinks)
|
|
real_path := file_path.realpath()
|
|
|
|
// Check if path exists
|
|
if file_path.exists() {
|
|
// Path exists
|
|
}
|
|
```
|
|
|
|
## Path Properties and Methods
|
|
|
|
### Path Types
|
|
|
|
```v
|
|
// Check if path is a file
|
|
if file_path.is_file() {
|
|
// Handle as file
|
|
}
|
|
|
|
// Check if path is a directory
|
|
if dir_path.is_dir() {
|
|
// Handle as directory
|
|
}
|
|
|
|
// Check if path is a symlink
|
|
if file_path.is_link() {
|
|
// Handle as symlink
|
|
}
|
|
```
|
|
|
|
### Path Normalization
|
|
|
|
```v
|
|
// Normalize path (remove extra slashes, resolve . and ..)
|
|
normalized_path := file_path.path_normalize()
|
|
|
|
// Get path directory
|
|
dir_path := file_path.path_dir()
|
|
|
|
// Get path name without extension
|
|
name_no_ext := file_path.name_no_ext()
|
|
```
|
|
|
|
## File and Directory Operations
|
|
|
|
### File Operations
|
|
|
|
```v
|
|
// Write to file
|
|
file_path.write("Content to write")!
|
|
|
|
// Read from file
|
|
content := file_path.read()!
|
|
|
|
// Delete file
|
|
file_path.delete()!
|
|
```
|
|
|
|
### Directory Operations
|
|
|
|
```v
|
|
// Create directory
|
|
mut dir := pathlib.get_dir(
|
|
path: "path/to/new/dir"
|
|
create: true
|
|
)!
|
|
|
|
// List directory contents
|
|
mut dir_list := dir.list()!
|
|
|
|
// Delete directory
|
|
dir.delete()!
|
|
```
|
|
|
|
### Symlink Operations
|
|
|
|
```v
|
|
// Create symlink
|
|
file_path.link("path/to/symlink", delete_exists: true)!
|
|
|
|
// Resolve symlink
|
|
real_path := file_path.realpath()
|
|
```
|
|
|
|
## Advanced Operations
|
|
|
|
### Path Copying
|
|
|
|
```v
|
|
// Copy file to destination
|
|
file_path.copy(dest: "path/to/destination")!
|
|
```
|
|
|
|
### Recursive Operations
|
|
|
|
```v
|
|
// List directory recursively
|
|
mut recursive_list := dir.list(recursive: true)!
|
|
|
|
// Delete directory recursively
|
|
dir.delete()!
|
|
```
|
|
|
|
### Path Filtering
|
|
|
|
```v
|
|
// List files matching pattern
|
|
mut filtered_list := dir.list(
|
|
regex: [r".*\.txt$"],
|
|
recursive: true
|
|
)!
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### Error Handling
|
|
|
|
```v
|
|
if file_path.exists() {
|
|
// Safe to operate
|
|
} else {
|
|
// Handle missing file
|
|
}
|
|
```
|
|
|
|
# Redisclient Module
|
|
|
|
The `redisclient` module in Herolib provides a comprehensive client for interacting with Redis, supporting various commands, caching, queues, and RPC mechanisms.
|
|
|
|
## Key Features
|
|
|
|
- **Direct Redis Commands**: Access to a wide range of Redis commands (strings, hashes, lists, keys, etc.).
|
|
- **Caching**: Built-in caching mechanism with namespace support and expiration.
|
|
- **Queues**: Simple queue implementation using Redis lists.
|
|
- **RPC**: Remote Procedure Call (RPC) functionality over Redis queues for inter-service communication.
|
|
|
|
## Basic Usage
|
|
|
|
To get a Redis client instance, use `redisclient.core_get()`. By default, it connects to `127.0.0.1:6379`. You can specify a different address and port using the `RedisURL` struct.
|
|
|
|
```v
|
|
import incubaid.herolib.core.redisclient
|
|
|
|
// Connect to default Redis instance (127.0.0.1:6379)
|
|
mut redis := redisclient.core_get()!
|
|
|
|
// Or connect to a specific Redis instance
|
|
// mut redis_url := redisclient.RedisURL{address: 'my.redis.server', port: 6380}
|
|
// mut redis := redisclient.core_get(redis_url)!
|
|
|
|
// Example: Set and Get a key
|
|
redis.set('mykey', 'myvalue')!
|
|
value := redis.get('mykey')!
|
|
// assert value == 'myvalue'
|
|
|
|
// Example: Check if a key exists
|
|
exists := redis.exists('mykey')!
|
|
// assert exists == true
|
|
|
|
// Example: Delete a key
|
|
redis.del('mykey')!
|
|
```
|
|
|
|
## Redis Commands
|
|
|
|
The `Redis` object provides methods for most standard Redis commands. Here are some examples:
|
|
|
|
### String Commands
|
|
|
|
- `set(key string, value string) !`: Sets the string value of a key.
|
|
- `get(key string) !string`: Gets the string value of a key.
|
|
- `set_ex(key string, value string, ex string) !`: Sets a key with an expiration time in seconds.
|
|
- `incr(key string) !int`: Increments the integer value of a key by one.
|
|
- `decr(key string) !int`: Decrements the integer value of a key by one.
|
|
- `append(key string, value string) !int`: Appends a value to a key.
|
|
- `strlen(key string) !int`: Gets the length of the value stored in a key.
|
|
|
|
```v
|
|
redis.set('counter', '10')!
|
|
redis.incr('counter')! // counter is now 11
|
|
val := redis.get('counter')! // "11"
|
|
```
|
|
|
|
### Hash Commands
|
|
|
|
- `hset(key string, skey string, value string) !`: Sets the string value of a hash field.
|
|
- `hget(key string, skey string) !string`: Gets the value of a hash field.
|
|
- `hgetall(key string) !map[string]string`: Gets all fields and values in a hash.
|
|
- `hexists(key string, skey string) !bool`: Checks if a hash field exists.
|
|
- `hdel(key string, skey string) !int`: Deletes one or more hash fields.
|
|
|
|
```v
|
|
redis.hset('user:1', 'name', 'John Doe')!
|
|
redis.hset('user:1', 'email', 'john/@example.com')!
|
|
user_name := redis.hget('user:1', 'name')! // "John Doe"
|
|
user_data := redis.hgetall('user:1')! // map['name':'John Doe', 'email':'john/@example.com']
|
|
```
|
|
|
|
### List Commands
|
|
|
|
- `lpush(key string, element string) !int`: Inserts all specified values at the head of the list stored at key.
|
|
- `rpush(key string, element string) !int`: Inserts all specified values at the tail of the list stored at key.
|
|
- `lpop(key string) !string`: Removes and returns the first element of the list stored at key.
|
|
- `rpop(key string) !string`: Removes and returns the last element of the list stored at key.
|
|
- `llen(key string) !int`: Gets the length of a list.
|
|
- `lrange(key string, start int, end int) ![]resp.RValue`: Gets a range of elements from a list.
|
|
|
|
```v
|
|
redis.lpush('mylist', 'item1')!
|
|
redis.rpush('mylist', 'item2')!
|
|
first_item := redis.lpop('mylist')! // "item1"
|
|
```
|
|
|
|
### Set Commands
|
|
|
|
- `sadd(key string, members []string) !int`: Adds the specified members to the set stored at key.
|
|
- `smismember(key string, members []string) ![]int`: Returns if member is a member of the set stored at key.
|
|
|
|
```v
|
|
redis.sadd('myset', ['member1', 'member2'])!
|
|
is_member := redis.smismember('myset', ['member1', 'member3'])! // [1, 0]
|
|
```
|
|
|
|
### Key Management
|
|
|
|
- `keys(pattern string) ![]string`: Finds all keys matching the given pattern.
|
|
- `del(key string) !int`: Deletes a key.
|
|
- `expire(key string, seconds int) !int`: Sets a key's time to live in seconds.
|
|
- `ttl(key string) !int`: Gets the time to live for a key in seconds.
|
|
- `flushall() !`: Deletes all the keys of all the existing databases.
|
|
- `flushdb() !`: Deletes all the keys of the currently selected database.
|
|
- `selectdb(database int) !`: Changes the selected database.
|
|
|
|
```v
|
|
redis.set('temp_key', 'value')!
|
|
redis.expire('temp_key', 60)! // Expires in 60 seconds
|
|
```
|
|
|
|
## Redis Cache
|
|
|
|
The `RedisCache` struct provides a convenient way to implement caching using Redis.
|
|
|
|
```v
|
|
import incubaid.herolib.core.redisclient
|
|
|
|
mut redis := redisclient.core_get()!
|
|
mut cache := redis.cache('my_app_cache')
|
|
|
|
// Set a value in cache with expiration (e.g., 3600 seconds)
|
|
cache.set('user:profile:123', '{ "name": "Alice" }', 3600)!
|
|
|
|
// Get a value from cache
|
|
cached_data := cache.get('user:profile:123') or {
|
|
// Cache miss, fetch from source
|
|
println('Cache miss for user:profile:123')
|
|
return
|
|
}
|
|
// println('Cached data: ${cached_data}')
|
|
|
|
// Check if a key exists in cache
|
|
exists := cache.exists('user:profile:123')
|
|
// assert exists == true
|
|
|
|
// Reset the cache for the namespace
|
|
cache.reset()!
|
|
```
|
|
|
|
## Redis Queue
|
|
|
|
The `RedisQueue` struct provides a simple queue mechanism using Redis lists.
|
|
|
|
```v
|
|
import incubaid.herolib.core.redisclient
|
|
import time
|
|
|
|
mut redis := redisclient.core_get()!
|
|
mut my_queue := redis.queue_get('my_task_queue')
|
|
|
|
// Add items to the queue
|
|
my_queue.add('task1')!
|
|
my_queue.add('task2')!
|
|
|
|
// Get an item from the queue with a timeout (e.g., 1000 milliseconds)
|
|
task := my_queue.get(1000)!
|
|
// assert task == 'task1'
|
|
|
|
// Pop an item without timeout (returns error if no item)
|
|
task2 := my_queue.pop()!
|
|
// assert task2 == 'task2'
|
|
```
|
|
|
|
## Redis RPC
|
|
|
|
The `RedisRpc` struct enables Remote Procedure Call (RPC) over Redis, allowing services to communicate by sending messages to queues and waiting for responses.
|
|
|
|
```v
|
|
import incubaid.herolib.core.redisclient
|
|
import json
|
|
import time
|
|
|
|
mut redis := redisclient.core_get()!
|
|
mut rpc_client := redis.rpc_get('my_rpc_service')
|
|
|
|
// Define a function to process RPC requests (server-side)
|
|
fn my_rpc_processor(cmd string, data string) !string {
|
|
// Simulate some processing based on cmd and data
|
|
return 'Processed: cmd=${cmd}, data=${data}'
|
|
}
|
|
|
|
// --- Client Side (calling the RPC) ---
|
|
// Call the RPC service
|
|
response := rpc_client.call(
|
|
cmd: 'greet',
|
|
data: '{"name": "World"}',
|
|
wait: true,
|
|
timeout: 5000 // 5 seconds timeout
|
|
)!
|
|
// println('RPC Response: ${response}')
|
|
// assert response == 'Processed: cmd=greet, data={"name": "World"}'
|
|
|
|
// --- Server Side (processing RPC requests) ---
|
|
// In a separate goroutine or process, you would run:
|
|
// rpc_client.process(my_rpc_processor, timeout: 0)! // timeout 0 means no timeout, keeps processing
|
|
|
|
// Example of how to process a single request (for testing/demonstration)
|
|
// In a real application, this would be in a loop or a background worker
|
|
// return_queue_name := rpc_client.process(my_rpc_processor, timeout: 1000)!
|
|
// result := rpc_client.result(1000, return_queue_name)!
|
|
// println('Processed result: ${result}')
|
|
```
|
|
|
|
# TextTools Module
|
|
|
|
The `texttools` module provides a comprehensive set of utilities for text manipulation and processing.
|
|
|
|
## Functions and Examples
|
|
|
|
```v
|
|
import incubaid.herolib.core.texttools
|
|
|
|
assert hello_world == texttools.name_fix("Hello World!")
|
|
|
|
```
|
|
|
|
### Name/Path Processing
|
|
|
|
* `name_fix(name string) string`: Normalizes filenames and paths.
|
|
- `name_fix_keepspace(name string) !string`: Like name_fix but preserves spaces.
|
|
- `name_fix_no_ext(name_ string) string`: Removes file extension.
|
|
- `name_fix_snake_to_pascal(name string) string`: Converts snake_case to PascalCase.
|
|
|
|
```v
|
|
name := texttools.name_fix_snake_to_pascal("hello_world") // Result: "HelloWorld"
|
|
```
|
|
|
|
* `snake_case(name string) string`: Converts PascalCase to snake_case.
|
|
|
|
```v
|
|
name := texttools.snake_case("HelloWorld") // Result: "hello_world"
|
|
```
|
|
|
|
* `name_split(name string) !(string, string)`: Splits name into site and page components.
|
|
|
|
### Text Cleaning
|
|
|
|
* `name_clean(r string) string`: Normalizes names by removing special characters.
|
|
|
|
```v
|
|
name := texttools.name_clean("Hello/@World!") // Result: "HelloWorld"
|
|
```
|
|
|
|
* `ascii_clean(r string) string`: Removes all non-ASCII characters.
|
|
- `remove_empty_lines(text string) string`: Removes empty lines from text.
|
|
|
|
```v
|
|
text := texttools.remove_empty_lines("line1\n\nline2\n\n\nline3") // Result: "line1\nline2\nline3"
|
|
```
|
|
|
|
* `remove_double_lines(text string) string`: Removes consecutive empty lines.
|
|
- `remove_empty_js_blocks(text string) string`: Removes empty code blocks (```...```).
|
|
|
|
### Command Line Parsing
|
|
|
|
* `cmd_line_args_parser(text string) ![]string`: Parses command line arguments with support for quotes and escaping.
|
|
|
|
```v
|
|
args := texttools.cmd_line_args_parser("'arg with spaces' --flag=value") // Result: ['arg with spaces', '--flag=value']
|
|
```
|
|
|
|
* `text_remove_quotes(text string) string`: Removes quoted sections from text.
|
|
- `check_exists_outside_quotes(text string, items []string) bool`: Checks if items exist in text outside of quotes.
|
|
|
|
### Text Expansion
|
|
|
|
* `expand(txt_ string, l int, expand_with string) string`: Expands text to a specified length with a given character.
|
|
|
|
### Indentation
|
|
|
|
* `indent(text string, prefix string) string`: Adds indentation prefix to each line.
|
|
|
|
```v
|
|
text := texttools.indent("line1\nline2", " ") // Result: " line1\n line2\n"
|
|
```
|
|
|
|
* `dedent(text string) string`: Removes common leading whitespace from every line.
|
|
|
|
```v
|
|
text := texttools.dedent(" line1\n line2") // Result: "line1\nline2"
|
|
```
|
|
|
|
### String Validation
|
|
|
|
* `is_int(text string) bool`: Checks if text contains only digits.
|
|
- `is_upper_text(text string) bool`: Checks if text contains only uppercase letters.
|
|
|
|
### Multiline Processing
|
|
|
|
* `multiline_to_single(text string) !string`: Converts multiline text to a single line with proper escaping.
|
|
|
|
### Text Splitting
|
|
|
|
* `split_smart(t string, delimiter_ string) []string`: Intelligent string splitting that respects quotes.
|
|
|
|
### Tokenization
|
|
|
|
* `tokenize(text_ string) TokenizerResult`: Tokenizes text into meaningful parts.
|
|
- `text_token_replace(text string, tofind string, replacewith string) !string`: Replaces tokens in text.
|
|
|
|
### Version Parsing
|
|
|
|
* `version(text_ string) int`: Converts version strings to comparable integers.
|
|
|
|
```v
|
|
ver := texttools.version("v0.4.36") // Result: 4036
|
|
ver = texttools.version("v1.4.36") // Result: 1004036
|
|
```
|
|
|
|
### Formatting
|
|
|
|
* `format_rfc1123(t time.Time) string`: Formats a time.Time object into RFC 1123 format.
|
|
|
|
### Array Operations
|
|
|
|
* `to_array(r string) []string`: Converts a comma or newline separated list to an array of strings.
|
|
|
|
```v
|
|
text := "item1,item2,item3"
|
|
array := texttools.to_array(text) // Result: ['item1', 'item2', 'item3']
|
|
```
|
|
|
|
* `to_array_int(r string) []int`: Converts a text list to an array of integers.
|
|
- `to_map(mapstring string, line string, delimiter_ string) map[string]string`: Intelligent mapping of a line to a map based on a template.
|
|
|
|
```v
|
|
r := texttools.to_map("name,-,-,-,-,pid,-,-,-,-,path",
|
|
"root 304 0.0 0.0 408185328 1360 ?? S 16Dec23 0:34.06 /usr/sbin/distnoted")
|
|
// Result: {'name': 'root', 'pid': '1360', 'path': '/usr/sbin/distnoted'}
|
|
```
|
|
|
|
```
|
|
|
|
# module ui.console
|
|
|
|
has mechanisms to print better to console, see the methods below
|
|
|
|
import as
|
|
|
|
```v
|
|
import incubaid.herolib.ui.console
|
|
|
|
```
|
|
|
|
## Methods
|
|
|
|
````v
|
|
|
|
fn clear()
|
|
//reset the console screen
|
|
|
|
fn color_bg(c BackgroundColor) string
|
|
// will give ansi codes to change background color . dont forget to call reset to change back to normal
|
|
|
|
fn color_fg(c ForegroundColor) string
|
|
// will give ansi codes to change foreground color . don't forget to call reset to change back to normal
|
|
|
|
struct PrintArgs {
|
|
pub mut:
|
|
foreground ForegroundColor
|
|
background BackgroundColor
|
|
text string
|
|
style Style
|
|
reset_before bool = true
|
|
reset_after bool = true
|
|
}
|
|
|
|
fn cprint(args PrintArgs)
|
|
// print with colors, reset...
|
|
// ```
|
|
// foreground ForegroundColor
|
|
// background BackgroundColor
|
|
// text string
|
|
// style Style
|
|
// reset_before bool = true
|
|
// reset_after bool = true
|
|
// ```
|
|
|
|
fn cprintln(args_ PrintArgs)
|
|
|
|
fn expand(txt_ string, l int, with string) string
|
|
// expand text till length l, with string which is normally ' '
|
|
|
|
fn lf()
|
|
line feed
|
|
|
|
fn new() UIConsole
|
|
|
|
fn print_array(arr [][]string, delimiter string, sort bool)
|
|
// print 2 dimensional array, delimeter is between columns
|
|
|
|
fn print_debug(i IPrintable)
|
|
|
|
fn print_debug_title(title string, txt string)
|
|
|
|
fn print_green(txt string)
|
|
|
|
fn print_header(txt string)
|
|
|
|
fn print_item(txt string)
|
|
|
|
fn print_lf(nr int)
|
|
|
|
fn print_stderr(txt string)
|
|
|
|
fn print_stdout(txt string)
|
|
|
|
fn reset() string
|
|
|
|
fn silent_get() bool
|
|
|
|
fn silent_set()
|
|
|
|
fn silent_unset()
|
|
|
|
fn style(c Style) string
|
|
// will give ansi codes to change style . don't forget to call reset to change back to normal
|
|
|
|
fn trim(c_ string) string
|
|
|
|
````
|
|
|
|
## Console Object
|
|
|
|
Is used to ask feedback to users
|
|
|
|
```v
|
|
|
|
struct UIConsole {
|
|
pub mut:
|
|
x_max int = 80
|
|
y_max int = 60
|
|
prev_lf bool
|
|
prev_title bool
|
|
prev_item bool
|
|
}
|
|
|
|
//DropDownArgs:
|
|
// - description string
|
|
// - items []string
|
|
// - warning string
|
|
// - clear bool = true
|
|
|
|
|
|
fn (mut c UIConsole) ask_dropdown_int(args_ DropDownArgs) !int
|
|
// return the dropdown as an int
|
|
|
|
fn (mut c UIConsole) ask_dropdown_multiple(args_ DropDownArgs) ![]string
|
|
// result can be multiple, aloso can select all description string items []string warning string clear bool = true
|
|
|
|
fn (mut c UIConsole) ask_dropdown(args DropDownArgs) !string
|
|
// will return the string as given as response description
|
|
|
|
// QuestionArgs:
|
|
// - description string
|
|
// - question string
|
|
// - warning: string (if it goes wrong, which message to use)
|
|
// - reset bool = true
|
|
// - regex: to check what result need to be part of
|
|
// - minlen: min nr of chars
|
|
|
|
fn (mut c UIConsole) ask_question(args QuestionArgs) !string
|
|
|
|
fn (mut c UIConsole) ask_time(args QuestionArgs) !string
|
|
|
|
fn (mut c UIConsole) ask_date(args QuestionArgs) !string
|
|
|
|
fn (mut c UIConsole) ask_yesno(args YesNoArgs) !bool
|
|
// yes is true, no is false
|
|
// args:
|
|
// - description string
|
|
// - question string
|
|
// - warning string
|
|
// - clear bool = true
|
|
|
|
fn (mut c UIConsole) reset()
|
|
|
|
fn (mut c UIConsole) status() string
|
|
|
|
```
|
|
|
|
## enums
|
|
|
|
```v
|
|
enum BackgroundColor {
|
|
default_color = 49 // 'default' is a reserved keyword in V
|
|
black = 40
|
|
red = 41
|
|
green = 42
|
|
yellow = 43
|
|
blue = 44
|
|
magenta = 45
|
|
cyan = 46
|
|
light_gray = 47
|
|
dark_gray = 100
|
|
light_red = 101
|
|
light_green = 102
|
|
light_yellow = 103
|
|
light_blue = 104
|
|
light_magenta = 105
|
|
light_cyan = 106
|
|
white = 107
|
|
}
|
|
enum ForegroundColor {
|
|
default_color = 39 // 'default' is a reserved keyword in V
|
|
white = 97
|
|
black = 30
|
|
red = 31
|
|
green = 32
|
|
yellow = 33
|
|
blue = 34
|
|
magenta = 35
|
|
cyan = 36
|
|
light_gray = 37
|
|
dark_gray = 90
|
|
light_red = 91
|
|
light_green = 92
|
|
light_yellow = 93
|
|
light_blue = 94
|
|
light_magenta = 95
|
|
light_cyan = 96
|
|
}
|
|
enum Style {
|
|
normal = 99
|
|
bold = 1
|
|
dim = 2
|
|
underline = 4
|
|
blink = 5
|
|
reverse = 7
|
|
hidden = 8
|
|
}
|
|
|
|
```
|
|
|
|
# how to run the vshell example scripts
|
|
|
|
this is how we want example scripts to be, see the first line, always use like this
|
|
|
|
```v
|
|
#!/usr/bin/env -S v -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
|
|
|
import incubaid.herolib...
|
|
|
|
```
|
|
|
|
the files are in ~/code/github/incubaid/herolib/examples for herolib
|
|
|
|
## important instructions
|
|
|
|
- never use fn main() in a .vsh script
|
|
- always use the top line as in example above
|
|
- these scripts can be executed as is but can also use vrun $pathOfFile
|
|
|
|
# V TEMPLATES
|
|
|
|
V allows for easily using text templates, expanded at compile time to
|
|
V functions, that efficiently produce text output. This is especially
|
|
useful for templated HTML views, but the mechanism is general enough
|
|
to be used for other kinds of text output also.
|
|
|
|
## Template directives
|
|
|
|
Each template directive begins with an `/@` sign.
|
|
Some directives contain a `{}` block, others only have `''` (string) parameters.
|
|
|
|
Newlines on the beginning and end are ignored in `{}` blocks,
|
|
otherwise this (see [if](#if) for this syntax):
|
|
|
|
```html
|
|
/@if bool_val {
|
|
<span>This is shown if bool_val is true</span>
|
|
}
|
|
```
|
|
|
|
... would output:
|
|
|
|
```html
|
|
|
|
<span>This is shown if bool_val is true</span>
|
|
|
|
```
|
|
|
|
... which is less readable.
|
|
|
|
## if
|
|
|
|
The if directive, consists of three parts, the `/@if` tag, the condition (same syntax like in V)
|
|
and the `{}` block, where you can write html, which will be rendered if the condition is true:
|
|
|
|
```
|
|
/@if <condition> {}
|
|
```
|
|
|
|
### Example
|
|
|
|
```html
|
|
/@if bool_val {
|
|
<span>This is shown if bool_val is true</span>
|
|
}
|
|
```
|
|
|
|
One-liner:
|
|
|
|
```html
|
|
/@if bool_val { <span>This is shown if bool_val is true</span> }
|
|
```
|
|
|
|
The first example would result in:
|
|
|
|
```html
|
|
<span>This is shown if bool_val is true</span>
|
|
```
|
|
|
|
... while the one-liner results in:
|
|
|
|
```html
|
|
<span>This is shown if bool_val is true</span>
|
|
```
|
|
|
|
## for
|
|
|
|
The for directive consists of three parts, the `/@for` tag,
|
|
the condition (same syntax like in V) and the `{}` block,
|
|
where you can write text, rendered for each iteration of the loop:
|
|
|
|
```
|
|
/@for <condition> {}
|
|
```
|
|
|
|
### Example for /@for
|
|
|
|
```html
|
|
/@for i, val in my_vals {
|
|
<span>$i - $val</span>
|
|
}
|
|
```
|
|
|
|
One-liner:
|
|
|
|
```html
|
|
/@for i, val in my_vals { <span>$i - $val</span> }
|
|
```
|
|
|
|
The first example would result in:
|
|
|
|
```html
|
|
<span>0 - "First"</span>
|
|
<span>1 - "Second"</span>
|
|
<span>2 - "Third"</span>
|
|
...
|
|
```
|
|
|
|
... while the one-liner results in:
|
|
|
|
```html
|
|
<span>0 - "First"</span>
|
|
<span>1 - "Second"</span>
|
|
<span>2 - "Third"</span>
|
|
...
|
|
```
|
|
|
|
You can also write (and all other for condition syntaxes that are allowed in V):
|
|
|
|
```html
|
|
/@for i = 0; i < 5; i++ {
|
|
<span>$i</span>
|
|
}
|
|
```
|
|
|
|
## include
|
|
|
|
The include directive is for including other html files (which will be processed as well)
|
|
and consists of two parts, the `/@include` tag and a following `'<path>'` string.
|
|
The path parameter is relative to the template file being called.
|
|
|
|
### Example for the folder structure of a project using templates
|
|
|
|
```
|
|
Project root
|
|
/templates
|
|
- index.html
|
|
/headers
|
|
- base.html
|
|
```
|
|
|
|
`index.html`
|
|
|
|
```html
|
|
|
|
<div>/@include 'header/base'</div>
|
|
```
|
|
|
|
> Note that there shouldn't be a file suffix,
|
|
> it is automatically appended and only allows `html` files.
|
|
|
|
## js
|
|
|
|
The js directive consists of two parts, the `/@js` tag and `'<path>'` string,
|
|
where you can insert your src
|
|
|
|
```
|
|
/@js '<url>'
|
|
```
|
|
|
|
### Example for the /@js directive
|
|
|
|
```html
|
|
/@js 'myscripts.js'
|
|
```
|
|
|
|
# Variables
|
|
|
|
All variables, which are declared before the $tmpl can be used through the `/@{my_var}` syntax.
|
|
It's also possible to use properties of structs here like `/@{my_struct.prop}`.
|
|
|
|
# Escaping
|
|
|
|
The `/@` symbol starts a template directive. If you need to use `/@` as a regular
|
|
character within a template, escape it by using a double `/@` like this: `/@/@`.
|