feat(std-rfc/str): add str align (#16062)

This commit is contained in:
Tyarel8
2025-08-05 18:21:23 +02:00
committed by GitHub
parent f015409253
commit 8c2af9941c
2 changed files with 187 additions and 0 deletions

View File

@@ -129,3 +129,54 @@ export def unindent [
$text $text
| str replace -r --all $"\(?m\)^($indent_chars)" '' | str replace -r --all $"\(?m\)^($indent_chars)" ''
} }
alias "str align" = align
# Aligns each line in the input string to have the target in the same column through padding
@example "Align variable assignments" { [ "one = 1", "two = 2", "three = 3", "four = 4", "five = 5" ] | str align '=' } --result r#'one = 1
two = 2
three = 3
four = 4
five = 5'#
@example "Align variable assignments to the center" { [ "one = 1", "two = 2", "three = 3", "four = 4", "five = 5" ] | str align '=' --center } --result r#' one = 1
two = 2
three = 3
four = 4
five = 5'#
export def align [
target:string # Substring to align
--char (-c) = " " # Character to use for padding
--center (-C) # Add padding at the beginning of the line instead of before the target
--range (-r): range # The range of lines to align
]: [string -> string, list<string> -> string] {
# noop on empty string
if ($in | is-empty) { return "" }
let $input = $in | to text | lines
let $indexes = (
$input
| enumerate
| each {|x|
if $x.index in ($range | default 0..) {
$x.item | str index-of $target
} else {
-1
}
}
)
let $max = $indexes | math max
$input
| zip $indexes
| each {|x|
# Fold adding a `$char` at the index until they are in the same column
# If the substring is not in the line, the index is -1 and it is left as it is
seq 1 (if $x.1 == -1 { 0 } else { $max - $x.1 })
| reduce -f ($x.0 | split chars) {|_, acc|
let $idx = if $center { 0 } else { $x.1 }
$acc | insert $idx $char
}
| str join
}
| str join (char nl)
}

View File

@@ -291,3 +291,139 @@ def str-unindent_whitespace_works_with_tabs [] {
assert equal $actual $expected assert equal $actual $expected
} }
@test
def str-align_simple [] {
let actual = [
"let a = 1"
"let max = 2"
"let very_long_variable_name = 3"
] | str align '='
let expected = [
"let a = 1"
"let max = 2"
"let very_long_variable_name = 3"
] | str join "\n"
assert equal $actual $expected
}
@test
def str-align_center [] {
let actual = [
"a = 1"
"max = 2"
"very_long_variable_name = 3"
] | str align '=' --center
let expected = [
" a = 1"
" max = 2"
"very_long_variable_name = 3"
] | str join "\n"
assert equal $actual $expected
}
@test
def str-align_with_range [] {
let actual = r#'match 5 {
1.. => { print "More than zero" }
0 => { print "Zero" }
-1 => { print "Negative one" }
-119283 => { print "Very negative" }
}'# | str align '=>' --range 2..
let expected = r#'match 5 {
1.. => { print "More than zero" }
0 => { print "Zero" }
-1 => { print "Negative one" }
-119283 => { print "Very negative" }
}'# | lines | str join "\n"
assert equal $actual $expected
}
@test
def str-align_ignore_lines_with_no_target [] {
let actual = [
"let a = 1"
"let max = 2"
"# comment"
] | str align '='
let expected = [
"let a = 1"
"let max = 2"
"# comment"
] | str join "\n"
assert equal $actual $expected
}
@test
def str-align_use_different_char [] {
let actual = [
"=>"
"=====>"
] | str align '>' -c '='
let expected = [
"=====>"
"=====>"
] | str join "\n"
assert equal $actual $expected
}
@test
def str-align_multiple_target_in_line [] {
let actual = [
"print test # Hello # World"
"print hello there # test"
] | str align '#'
let expected = [
"print test # Hello # World"
"print hello there # test"
] | str join "\n"
assert equal $actual $expected
}
@test
def str-align_no_target [] {
let expected = [
"print test # Hello # World"
"print hello there # test"
] | str join "\n"
let actual = $expected | str align '='
assert equal $actual $expected
}
@test
def str-align_empty_target_noop [] {
let expected = [
"print test # Hello # World"
"print hello there # test"
] | str join "\n"
let actual = $expected | str align ''
assert equal $actual $expected
}
@test
def str-align_empty_input_noop [] {
let expected = ""
let actual = [] | str align '='
assert equal $actual $expected
}