diff --git a/functions/core/compare_versions.go b/functions/core/compare_versions.go new file mode 100644 index 00000000..d5cd91fd --- /dev/null +++ b/functions/core/compare_versions.go @@ -0,0 +1,36 @@ +package core + +import ( + "strconv" + "strings" +) + +// CompareVersions compares two semver strings (e.g. "v1.4.0", "1.2.3"). +// Returns -1 if a < b, 0 if equal, 1 if a > b. +func CompareVersions(a, b string) int { + pa := parseVersionParts(a) + pb := parseVersionParts(b) + for i := 0; i < 3; i++ { + if pa[i] < pb[i] { + return -1 + } + if pa[i] > pb[i] { + return 1 + } + } + return 0 +} + +func parseVersionParts(v string) [3]int { + v = strings.TrimPrefix(v, "v") + parts := strings.SplitN(v, ".", 3) + var nums [3]int + for i, p := range parts { + if i >= 3 { + break + } + n, _ := strconv.Atoi(p) + nums[i] = n + } + return nums +} diff --git a/functions/core/compare_versions.md b/functions/core/compare_versions.md new file mode 100644 index 00000000..ebc06271 --- /dev/null +++ b/functions/core/compare_versions.md @@ -0,0 +1,42 @@ +--- +name: compare_versions +kind: function +lang: go +domain: core +version: "1.0.0" +purity: pure +signature: "func CompareVersions(a, b string) int" +description: "Compara dos strings de version semantica (semver). Soporta formato con o sin prefijo 'v'. Retorna -1, 0 o 1." +tags: [core, version, semver, compare, parse] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [strconv, strings] +params: + - name: a + desc: "primera version (ej: 'v1.4.0' o '1.4.0')" + - name: b + desc: "segunda version" +output: "-1 si a < b, 0 si iguales, 1 si a > b" +tested: false +tests: [] +test_file_path: "" +file_path: "functions/core/compare_versions.go" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "installer/core/version.go" +--- + +## Ejemplo + +```go +core.CompareVersions("v1.4.0", "v1.3.9") // 1 +core.CompareVersions("1.0.0", "1.0.0") // 0 +core.CompareVersions("v0.9.0", "v1.0.0") // -1 +``` + +## Notas + +Compara major.minor.patch como enteros. Ignora pre-release tags y metadata (solo los 3 numeros). Partes faltantes se tratan como 0. diff --git a/functions/core/longest_common_prefix.go b/functions/core/longest_common_prefix.go new file mode 100644 index 00000000..5a3af419 --- /dev/null +++ b/functions/core/longest_common_prefix.go @@ -0,0 +1,21 @@ +package core + +import "strings" + +// LongestCommonPrefix returns the longest string that is a prefix of every item. +// Returns "" if the slice is empty or no common prefix exists. +func LongestCommonPrefix(items []string) string { + if len(items) == 0 { + return "" + } + prefix := items[0] + for _, item := range items[1:] { + for !strings.HasPrefix(item, prefix) { + if prefix == "" { + return "" + } + prefix = prefix[:len(prefix)-1] + } + } + return prefix +} diff --git a/functions/core/longest_common_prefix.md b/functions/core/longest_common_prefix.md new file mode 100644 index 00000000..474c3832 --- /dev/null +++ b/functions/core/longest_common_prefix.md @@ -0,0 +1,42 @@ +--- +name: longest_common_prefix +kind: function +lang: go +domain: core +version: "1.0.0" +purity: pure +signature: "func LongestCommonPrefix(items []string) string" +description: "Retorna el prefijo comun mas largo compartido por todos los strings del slice. Util para autocompletado de rutas y comandos." +tags: [core, string, prefix, autocomplete, common] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [strings] +params: + - name: items + desc: "slice de strings para buscar prefijo comun" +output: "prefijo comun mas largo, o vacio si no hay coincidencia" +tested: false +tests: [] +test_file_path: "" +file_path: "functions/core/longest_common_prefix.go" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "launcher/core/commands.go" +--- + +## Ejemplo + +```go +prefix := core.LongestCommonPrefix([]string{"/home/user/docs", "/home/user/downloads", "/home/user/desktop"}) +// prefix == "/home/user/d" + +empty := core.LongestCommonPrefix([]string{"abc", "xyz"}) +// empty == "" +``` + +## Notas + +Compara caracter por caracter acortando el prefijo progresivamente. Complejidad O(n*m) donde n es el numero de strings y m la longitud del prefijo. diff --git a/functions/core/parse_version.go b/functions/core/parse_version.go new file mode 100644 index 00000000..138a170b --- /dev/null +++ b/functions/core/parse_version.go @@ -0,0 +1,15 @@ +package core + +import "strings" + +// ParseVersion extracts the version tag from the first word of the first line. +// For example, "v1.4.0 - Description" returns "v1.4.0". +// Returns "" if the input is empty. +func ParseVersion(content string) string { + line := strings.SplitN(strings.TrimSpace(content), "\n", 2)[0] + word := strings.Fields(line) + if len(word) == 0 { + return "" + } + return word[0] +} diff --git a/functions/core/parse_version.md b/functions/core/parse_version.md new file mode 100644 index 00000000..322d5a47 --- /dev/null +++ b/functions/core/parse_version.md @@ -0,0 +1,42 @@ +--- +name: parse_version +kind: function +lang: go +domain: core +version: "1.0.0" +purity: pure +signature: "func ParseVersion(content string) string" +description: "Extrae el tag de version del primer campo de la primera linea de texto. Util para parsear archivos VERSION.txt o salida de comandos --version." +tags: [core, version, parse, text, extract] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [strings] +params: + - name: content + desc: "texto con version en la primera palabra de la primera linea" +output: "string con el tag de version (ej: 'v1.4.0'), o vacio" +tested: false +tests: [] +test_file_path: "" +file_path: "functions/core/parse_version.go" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "installer/core/version.go" +--- + +## Ejemplo + +```go +v := core.ParseVersion("v0.4.9 - Instalador Julia Windows (2026-02-28)") +// v == "v0.4.9" + +v2 := core.ParseVersion("1.0.0\nChangelog...") +// v2 == "1.0.0" +``` + +## Notas + +Toma solo el primer campo (separado por whitespace) de la primera linea. No valida formato semver — simplemente extrae el primer token. diff --git a/functions/core/rel_or_full.go b/functions/core/rel_or_full.go new file mode 100644 index 00000000..4779396a --- /dev/null +++ b/functions/core/rel_or_full.go @@ -0,0 +1,13 @@ +package core + +import "path/filepath" + +// RelOrFull returns target relative to base when possible, +// otherwise returns target unchanged. +func RelOrFull(base, target string) string { + rel, err := filepath.Rel(base, target) + if err != nil { + return target + } + return rel +} diff --git a/functions/core/rel_or_full.md b/functions/core/rel_or_full.md new file mode 100644 index 00000000..db1ad928 --- /dev/null +++ b/functions/core/rel_or_full.md @@ -0,0 +1,44 @@ +--- +name: rel_or_full +kind: function +lang: go +domain: core +version: "1.0.0" +purity: pure +signature: "func RelOrFull(base, target string) string" +description: "Retorna el path de target relativo a base. Si filepath.Rel falla, retorna target sin cambios. Util para mostrar paths cortos en UIs." +tags: [core, path, relative, filepath, display] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [path/filepath] +params: + - name: base + desc: "directorio base para calcular la ruta relativa" + - name: target + desc: "path absoluto o relativo a convertir" +output: "path relativo a base, o target original si la conversion falla" +tested: false +tests: [] +test_file_path: "" +file_path: "functions/core/rel_or_full.go" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "launcher/core/script_query.go" +--- + +## Ejemplo + +```go +rel := core.RelOrFull("/home/user/project", "/home/user/project/src/main.go") +// rel == "src/main.go" + +full := core.RelOrFull("/home/user", "/other/path") +// full == "../../other/path" +``` + +## Notas + +Wrapper seguro sobre `filepath.Rel` que nunca retorna error. Si los paths estan en volúmenes distintos (Windows), retorna el target original. diff --git a/functions/core/split_command_and_arg.go b/functions/core/split_command_and_arg.go new file mode 100644 index 00000000..e3ed01c1 --- /dev/null +++ b/functions/core/split_command_and_arg.go @@ -0,0 +1,20 @@ +package core + +import "strings" + +// SplitCommandAndArg splits "cmd arg" into its two parts. +// Returns (cmd, arg, true) if a space separator is found, +// or ("", "", false) if the input has no space or is empty. +func SplitCommandAndArg(input string) (cmd, arg string, ok bool) { + trimmed := strings.TrimSpace(input) + idx := strings.Index(trimmed, " ") + if idx == -1 { + return "", "", false + } + cmd = strings.TrimSpace(trimmed[:idx]) + arg = strings.TrimSpace(trimmed[idx+1:]) + if cmd == "" { + return "", "", false + } + return cmd, arg, true +} diff --git a/functions/core/split_command_and_arg.md b/functions/core/split_command_and_arg.md new file mode 100644 index 00000000..1a95c52e --- /dev/null +++ b/functions/core/split_command_and_arg.md @@ -0,0 +1,42 @@ +--- +name: split_command_and_arg +kind: function +lang: go +domain: core +version: "1.0.0" +purity: pure +signature: "func SplitCommandAndArg(input string) (cmd, arg string, ok bool)" +description: "Separa un string 'comando argumento' en sus dos partes por el primer espacio. Retorna ok=false si no hay espacio o el input esta vacio." +tags: [core, string, split, command, parse, cli] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [strings] +params: + - name: input + desc: "string con formato 'comando argumento'" +output: "tupla (cmd, arg, ok) donde ok indica si se encontro separador" +tested: false +tests: [] +test_file_path: "" +file_path: "functions/core/split_command_and_arg.go" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "launcher/core/commands.go" +--- + +## Ejemplo + +```go +cmd, arg, ok := core.SplitCommandAndArg("cd /home/user") +// cmd == "cd", arg == "/home/user", ok == true + +_, _, ok2 := core.SplitCommandAndArg("exit") +// ok2 == false +``` + +## Notas + +Solo separa por el primer espacio. El argumento puede contener espacios adicionales. Trims whitespace en ambos extremos del input y de cada parte.