Repository: neovim/neovim
Pull request #34122: perf(runtime): vim.trim for long only whitespace strings
Author: login: monkoose
Labels: name: performance
description: performance, latency, cpu/memory usage
Created: 2025-05-22T10:10:19Z | Merged: 2025-05-26T21:41:13Z

To increase execution speed of vim.trim for long only whitespace strings it requires to firstly strip whitespace characters with `gsub('^%s+', '')` and only then get match with `match('^.*%S').

Changes to `vim_spec.lua` were made to cover more cases and fix wrong usage of `assert` instead of `eq`.

Benchmarks can be found here https://github.com/neovim/neovim/pull/34122#issuecomment-2902291021

Closes #34097 


Linked issue #34097: vim.trim is slow in worse case scenario
### Problem

vim.trim() uses `s:match('^%s*(.*%S)') or ''` which is slow (can take seconds) for long only whitespace strings and comparably slower than my suggestion with long whitespaces at the end.

The fastest thing I have found is using `vim.lpeg` and `vim.re`
```lua
local trim_pattern = vim.re.compile("%s* {(%s* %S+)*}")
local function trim(s)
    return vim.lpeg.match(trim_pattern, s)
end
```

Benchmark file is here https://gist.github.com/monkoose/8931f5e43d935da2c387650079826b8b


### Expected behavior

vim.trim() should not drastically degrate for any input.
Linked issue comments: user: login: glepnir
created_at: 2025-05-20T11:07:05Z
body: a pure lua 5.1 implementation and based on your bench mark

<details>
<summary>Benchmark </summary>

```lua
local function benchmark(func, ...)
  func(...)
  local start = os.clock()
  local result = func(...)
  local elapsed = os.clock() - start

  print(string.format('Time: %.3f ms', elapsed * 1000))
end

local function trim(str)
  vim.validate('s', str, 'string')
  return str:match('^%s*(.*%S)') or ''
end

local lpeg = vim.lpeg
local trim_pattern = vim.re.compile('%s* {(%s* %S+)*}')
local function trim2(s)
  vim.validate('s', s, 'string')
  return lpeg.match(trim_pattern, s)
end

local function trim3(s)
  vim.validate('s', s, 'string')
  if s == '' then
    return ''
  end

  if s:byte(1) > 32 and s:byte(#s) > 32 then
    return s
  end

  local start = nil
  local stop = nil

  for i = 1, #s do
    if s:byte(i) > 32 then
      start = i
      break
    end
  end

  if not start then
    return ''
  end

  for i = #s, start, -1 do
    if s:byte(i) > 32 then
      stop = i
      break
    end
  end

  return s:sub(start, stop)
end

local str = [[
                                                                                                              
                                                                                                             
                                                                                                             
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
   ]]
local str2 = ' \n \f hello \r \v'

local str3 = [[
                                                                                                              
                                                                                                             
                                                                                                             
                                                                                                              
                                                                                                              
                                                                                                              
      hello                                                                                                       
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
   ]]

benchmark(trim, str)
benchmark(trim2, str)
benchmark(trim3, str)
print('----------------------')

benchmark(trim, str2)
benchmark(trim2, str2)
benchmark(trim3, str2)
print('----------------------')

benchmark(trim, str3)
benchmark(trim2, str3)
benchmark(trim3, str3)
print('----------------------')
````
</details>

output 
```
λ nvim -l bench.lua
Time: 231.568 ms
Time: 0.006 ms
Time: 0.005 ms
----------------------
Time: 0.002 ms
Time: 0.000 ms
Time: 0.000 ms
----------------------
Time: 0.050 ms
Time: 0.006 ms
Time: 0.007 ms
----------------------
````
author_association: MEMBER
user: login: monkoose
created_at: 2025-05-20T11:42:24Z
body: Thanks for testing and implementation. Personally I don't mind any implementation which  have no issues of the current `vim.trim()`.
LuaJIT is optimizing loops pretty good. If you run benchmarks without first `func(...)` in it, then first call to trim with your implementation is visibly slower. But after it on my PC it is faster that lpeg version.
author_association: CONTRIBUTOR
user: login: glepnir
created_at: 2025-05-20T11:46:09Z
body: luajit is not considered because neovim can run without it. just cache some function like this
```lua
local function trim4(s)
  vim.validate('s', s, 'string')
  local byte, sub = string.byte, string.sub
  local len = #s

  if len == 0 then return '' end

  if byte(s, 1) > 32 and byte(s, len) > 32 then return s end

  local start = 1
  while start <= len and byte(s, start) <= 32 do
    start = start + 1
  end

  if start > len then return '' end

  local stop = len
  while stop >= start and byte(s, stop) <= 32 do
    stop = stop - 1
  end

  return sub(s, start, stop)
end
```

```
λ nvim -l bench.lua
Time: 238.555 ms
Time: 0.005 ms
Time: 0.006 ms
Time: 0.008 ms
----------------------
Time: 0.001 ms
Time: 0.000 ms
Time: 0.000 ms
Time: 0.001 ms
----------------------
Time: 0.047 ms
Time: 0.008 ms
Time: 0.007 ms
Time: 0.008 ms
----------------------

Commen first func call
λ nvim -l bench.lua
Time: 239.300 ms
Time: 0.014 ms
Time: 0.040 ms
Time: 0.017 ms
----------------------
Time: 0.001 ms
Time: 0.000 ms
Time: 0.001 ms
Time: 0.000 ms
----------------------
Time: 0.052 ms
Time: 0.007 ms
Time: 0.019 ms
Time: 0.007 ms
----------------------
```

author_association: MEMBER
user: login: justinmk
created_at: 2025-05-22T09:24:04Z
body: send a PR? a compiled pattern certainly seems like a good idea.
author_association: MEMBER
user: login: monkoose
created_at: 2025-05-22T10:10:47Z
body: Done.
author_association: CONTRIBUTOR

Diff:
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index fa66e18ac47e8b..73b74081188d2d 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -801,7 +801,9 @@ end
 ---@return string String with whitespace removed from its beginning and end
 function vim.trim(s)
   vim.validate('s', s, 'string')
-  return s:match('^%s*(.*%S)') or ''
+  -- `s:match('^%s*(.*%S)')` is slow for long whitespace strings,
+  -- so we are forced to split it into two parts to prevent this
+  return s:gsub('^%s+', ''):match('^.*%S') or ''
 end
 
 --- Escapes magic chars in |lua-pattern|s.
diff --git a/test/benchmark/trim_spec.lua b/test/benchmark/trim_spec.lua
new file mode 100644
index 00000000000000..29b7793c36c56a
--- /dev/null
+++ b/test/benchmark/trim_spec.lua
@@ -0,0 +1,70 @@
+describe('vim.trim()', function()
+  --- @param t number[]
+  local function mean(t)
+    assert(#t > 0)
+    local sum = 0
+    for _, v in ipairs(t) do
+      sum = sum + v
+    end
+    return sum / #t
+  end
+
+  --- @param t number[]
+  local function median(t)
+    local len = #t
+    if len % 2 == 0 then
+      return t[len / 2]
+    end
+    return t[(len + 1) / 2]
+  end
+
+  --- @param f fun(t: number[]): table<number, number|string|table>
+  local function measure(f, input, N)
+    local stats = {} ---@type number[]
+    for _ = 1, N do
+      local tic = vim.uv.hrtime()
+      f(input)
+      local toc = vim.uv.hrtime()
+      stats[#stats + 1] = (toc - tic) / 1000000
+    end
+    table.sort(stats)
+    print(
+      string.format(
+        '\nN: %d, Min: %0.6f ms, Max: %0.6f ms, Median: %0.6f ms, Mean: %0.6f ms',
+        N,
+        math.min(unpack(stats)),
+        math.max(unpack(stats)),
+        median(stats),
+        mean(stats)
+      )
+    )
+  end
+
+  local strings = {
+    ['10000 whitespace characters'] = string.rep(' ', 10000),
+    ['10000 whitespace characters and one non-whitespace at the end'] = string.rep(' ', 10000)
+      .. '0',
+    ['10000 whitespace characters and one non-whitespace at the start'] = '0'
+      .. string.rep(' ', 10000),
+    ['10000 non-whitespace characters'] = string.rep('0', 10000),
+    ['10000 whitespace and one non-whitespace in the middle'] = string.rep(' ', 5000)
+      .. 'a'
+      .. string.rep(' ', 5000),
+    ['10000 whitespace characters surrounded by non-whitespace'] = '0'
+      .. string.rep(' ', 10000)
+      .. '0',
+    ['10000 non-whitespace characters surrounded by whitespace'] = ' '
+      .. string.rep('0', 10000)
+      .. ' ',
+  }
+
+  --- @type string[]
+  local string_names = vim.tbl_keys(strings)
+  table.sort(string_names)
+
+  for _, name in ipairs(string_names) do
+    it(name, function()
+      measure(vim.trim, strings[name], 100)
+    end)
+  end
+end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 0a76af70d1125b..33bb6d9d4ae234 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -719,10 +719,12 @@ describe('lua stdlib', function()
       { ' b  ', 'b' },
       { '\tc', 'c' },
       { 'r\n', 'r' },
+      { '', '' },
+      { ' \t \n', '' },
     }
 
     for _, q in ipairs(trims) do
-      assert(q[2], trim(q[1]))
+      eq(q[2], trim(q[1]))
     end
 
     -- Validates args.


Reviews:
user: login: justinmk
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-22T12:05:15Z
user: login: justinmk
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-22T12:05:45Z
user: login: monkoose
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T12:11:28Z
user: login: justinmk
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-22T12:13:15Z
user: login: monkoose
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T12:13:50Z
user: login: monkoose
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T12:16:58Z
user: login: echasnovski
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-22T16:35:39Z
user: login: lucario387
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T01:23:55Z
user: login: monkoose
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T05:21:03Z
user: login: lewis6991
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-23T08:16:11Z
user: login: monkoose
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T08:32:20Z
user: login: echasnovski
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-23T16:46:50Z
user: login: lewis6991
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-24T09:39:23Z
user: login: monkoose
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-24T10:08:54Z
user: login: echasnovski
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-24T10:25:49Z

Review comments:
diff_hunk: @@ -793,6 +793,7 @@ function vim._list_remove(t, first, last)
   end
 end
 
+local _trim_pattern = vim.re.compile('%s* {(%s* %S+)*}')
path: runtime/lua/vim/shared.lua
user: login: justinmk
body: `shared.lua` is special because the test runner uses it with a limited Nvim (`nvim -ll`) which doesn't have some modules like `vim.re`.

    /Users/runner/work/neovim/neovim/runtime/lua/vim/shared.lua:796: attempt to index field 're' (a nil value)

to workaround this, try:

```suggestion
local _trim_pattern = vim.re and vim.re.compile('%s* {(%s* %S+)*}') or nil
```

then below,

    return _trim_pattern and _trim_pattern:match(s) or (s:match('^%s*(.*%S)') or '')

alternatively, could make the `vim.re` module available by updating `src/nvim/CMakeLists.txt` (I think?). @bfredl @zeertzjq any reason `vim.re` can't be available for `nvim -ll` ?
created_at: 2025-05-22T12:05:15Z
author_association: MEMBER
diff_hunk: @@ -801,7 +802,7 @@ end
 ---@return string String with whitespace removed from its beginning and end
 function vim.trim(s)
   vim.validate('s', s, 'string')
-  return s:match('^%s*(.*%S)') or ''
+  return _trim_pattern:match(s)
path: runtime/lua/vim/shared.lua
user: login: justinmk
body: will it return empty string if there's no match? or is `or ''` needed?
created_at: 2025-05-22T12:05:44Z
author_association: MEMBER
diff_hunk: @@ -793,6 +793,7 @@ function vim._list_remove(t, first, last)
   end
 end
 
+local _trim_pattern = vim.re.compile('%s* {(%s* %S+)*}')
path: runtime/lua/vim/shared.lua
user: login: monkoose
body: @justinmk Maybe then using lua loops with string.byte which is proposed by @glepnir in the issue is a better solution? And it is as fast if not faster than lpeg?
created_at: 2025-05-22T12:11:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -793,6 +793,7 @@ function vim._list_remove(t, first, last)
   end
 end
 
+local _trim_pattern = vim.re.compile('%s* {(%s* %S+)*}')
path: runtime/lua/vim/shared.lua
user: login: justinmk
body: If it's not a lot of code, then sure. But we probably can make `vim.re` available.
created_at: 2025-05-22T12:13:15Z
author_association: MEMBER
diff_hunk: @@ -801,7 +802,7 @@ end
 ---@return string String with whitespace removed from its beginning and end
 function vim.trim(s)
   vim.validate('s', s, 'string')
-  return s:match('^%s*(.*%S)') or ''
+  return _trim_pattern:match(s)
path: runtime/lua/vim/shared.lua
user: login: monkoose
body: Yes. `{(%s* %S+)*}`.
`{}` - means return capture, not index
`()*` returns 0 or as many as possible matches. And if there is 0 it will return empty string, previsously trimming whitespaces with `^%s*`.
created_at: 2025-05-22T12:13:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -801,7 +802,7 @@ end
 ---@return string String with whitespace removed from its beginning and end
 function vim.trim(s)
   vim.validate('s', s, 'string')
-  return s:match('^%s*(.*%S)') or ''
+  return _trim_pattern:match(s)
path: runtime/lua/vim/shared.lua
user: login: monkoose
body: In any case https://github.com/neovim/neovim/blob/27bb814cb1b70b4e041eae22665bc93350f4fe56/test/functional/lua/vim_spec.lua#L712-L730 
Should be updated to include empty string for tests.
created_at: 2025-05-22T12:16:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -793,6 +793,7 @@ function vim._list_remove(t, first, last)
   end
 end
 
+local _trim_pattern = vim.re.compile('%s* {(%s* %S+)*}')
path: runtime/lua/vim/shared.lua
user: login: echasnovski
body: The ["conditional gsub"](https://github.com/neovim/neovim/pull/34122#issuecomment-2901559179) solution is not a lot of code. It also outperforms lpeg approach in the other edge case of the very wide string that doesn't need trimming.

The downside of the `vim.re` approach is that it will always source `require('vim.re')` on startup, which has not quite negligible effect. On my machine a `nvim --clean -u init-vimre.lua` with 'init-vimre.lua' containing single line `local _trim_pattern = vim.re.compile('%s* {(%s* %S+)*}')` adds about 0.7ms to startup compared to overall about 10.3 ms of "Embedded" part of startup.
created_at: 2025-05-22T16:35:39Z
author_association: MEMBER
diff_hunk: @@ -719,6 +719,10 @@ describe('lua stdlib', function()
       { ' b  ', 'b' },
       { '\tc', 'c' },
       { 'r\n', 'r' },
+      { '', '' },
+      { ' \t \n', '' },
+      -- double whitespace <C-k>IS
+      { '　f　', 'f' },
     }
 
     for _, q in ipairs(trims) do
path: test/functional/lua/vim_spec.lua
user: login: lucario387
body: Forgive me if I'm wrong but isn't this test only checking if `q[2]` is false or not, which means it never fails? Shouldn't it be `assert(q[2] == trim(q[1])`.
created_at: 2025-05-23T01:23:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -719,6 +719,10 @@ describe('lua stdlib', function()
       { ' b  ', 'b' },
       { '\tc', 'c' },
       { 'r\n', 'r' },
+      { '', '' },
+      { ' \t \n', '' },
+      -- double whitespace <C-k>IS
+      { '　f　', 'f' },
     }
 
     for _, q in ipairs(trims) do
path: test/functional/lua/vim_spec.lua
user: login: monkoose
body: @lucario387 you can overload easily in lua. So I haven't looked deeply into this tests "trusting" previous contributors. 
Maybe it should be `eq`? But I assume that is `assert` from busted lib, so I'm not sure.
created_at: 2025-05-23T05:21:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -801,7 +801,34 @@ end
 ---@return string String with whitespace removed from its beginning and end
 function vim.trim(s)
   vim.validate('s', s, 'string')
-  return s:match('^%s*(.*%S)') or ''
+  local len = #s
+  local byte = string.byte
+
+  if len == 0 then
+    return ''
+  end
+
+  -- `s` is already trimmed
+  if byte(s, 1) > 32 and byte(s, len) > 32 then
+    return s
+  end
+
+  local start = 1
+  while start <= len and byte(s, start) <= 32 do
path: runtime/lua/vim/shared.lua
user: login: lewis6991
body: Is less `<=32` safe to do here? I'm assuming that covers `\n\t` too?
created_at: 2025-05-23T08:16:06Z
author_association: MEMBER
diff_hunk: @@ -801,7 +801,34 @@ end
 ---@return string String with whitespace removed from its beginning and end
 function vim.trim(s)
   vim.validate('s', s, 'string')
-  return s:match('^%s*(.*%S)') or ''
+  local len = #s
+  local byte = string.byte
+
+  if len == 0 then
+    return ''
+  end
+
+  -- `s` is already trimmed
+  if byte(s, 1) > 32 and byte(s, len) > 32 then
+    return s
+  end
+
+  local start = 1
+  while start <= len and byte(s, start) <= 32 do
path: runtime/lua/vim/shared.lua
user: login: monkoose
body: Yes, everything below 32 is special (non printable) character and 32 is a space.

It passes tests.

created_at: 2025-05-23T08:32:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -801,7 +801,7 @@ end
 ---@return string String with whitespace removed from its beginning and end
 function vim.trim(s)
   vim.validate('s', s, 'string')
-  return s:match('^%s*(.*%S)') or ''
+  return s:gsub('^%s+', ''):match('^.*%S') or ''
path: runtime/lua/vim/shared.lua
user: login: lewis6991
body: Can you add a comment here explaining why we don't use just `match`. This I'll prevent anyone changing this in the future.
created_at: 2025-05-24T09:38:48Z
author_association: MEMBER
diff_hunk: @@ -801,7 +801,7 @@ end
 ---@return string String with whitespace removed from its beginning and end
 function vim.trim(s)
   vim.validate('s', s, 'string')
-  return s:match('^%s*(.*%S)') or ''
+  return s:gsub('^%s+', ''):match('^.*%S') or ''
path: runtime/lua/vim/shared.lua
user: login: monkoose
body: Done.
created_at: 2025-05-24T10:08:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -801,7 +801,9 @@ end
 ---@return string String with whitespace removed from its beginning and end
 function vim.trim(s)
   vim.validate('s', s, 'string')
-  return s:match('^%s*(.*%S)') or ''
+  -- `s:match('^%s*(.*%S)')` is slow for long whitespace strings,
+  -- so we are forced to split it into to parts to prevent this
path: runtime/lua/vim/shared.lua
user: login: echasnovski
body: Maybe also mention `gsub('%s+$', '')` case (as it is not intuitive)?

```suggestion
  -- `match('^%s*(.*%S)')` is slow for long whitespace strings
  -- `gsub('%s+$', '')` is slow for strings with many whitespace characters
  -- See PR #34122 for more details
```
created_at: 2025-05-24T10:25:49Z
author_association: MEMBER

PR comments:
user: login: monkoose
created_at: 2025-05-22T12:53:45Z
body: @bfredl @zeertzjq 
Is using this version better, than dealing with `vim.re` in `shared.lua`?
```lua
function vim.trim(s)
  vim.validate('s', s, 'string')
  local byte, sub = string.byte, string.sub
  local len = #s

  if len == 0 then return '' end

  if byte(s, 1) > 32 and byte(s, len) > 32 then return s end

  local start = 1
  while start <= len and byte(s, start) <= 32 do
    start = start + 1
  end

  if start > len then return '' end

  local stop = len
  while stop >= start and byte(s, stop) <= 32 do
    stop = stop - 1
  end

  return sub(s, start, stop)
end
```
author_association: CONTRIBUTOR
user: login: justinmk
created_at: 2025-05-22T13:37:20Z
body: discussed on matrix, likely will enable `vim.re` for shared.lua.
author_association: MEMBER
user: login: echasnovski
created_at: 2025-05-22T13:59:35Z
body: I am late to the party, but the following approach is more performant than current one and compares okay to compiled pattern for bad case:

```lua
local trim4 = function(s)
  return (s:gsub('^%s+', ''):gsub('%s+$', ''))
end
```

Output of benchmarking from [this comment](https://github.com/neovim/neovim/issues/34097#issuecomment-2893936586):

```
Time: 220.193 ms -- current
Time: 0.013 ms   -- lpeg
Time: 0.006 ms   -- @glepnir's mega performant
Time: 0.024 ms   -- two gsub
----------------------
Time: 0.001 ms
Time: 0.001 ms
Time: 0.001 ms
Time: 0.001 ms
----------------------
Time: 0.050 ms
Time: 0.014 ms
Time: 0.006 ms
Time: 0.024 ms
----------------------
```
author_association: MEMBER
user: login: monkoose
created_at: 2025-05-22T14:41:08Z
body: @echasnovski Benchmarks are incomplete. And your version degrades (not that much so) with long non-whitespace strings (I think I have tested something similar, and because I wasn't aware of `shared.lua` limitations I had come up with that solution). Try to replace spaces in str1 to any char). And current `string.match()` is good for long non-whitespace strings.

glepnir version behaves the best with any input. And it doesn't require changes to `shared.lua`. Maybe it is best solution?

author_association: CONTRIBUTOR
user: login: lucario387
created_at: 2025-05-22T14:43:32Z
body: I know it's not too frequent but the string.byte version doesn't trim double-width whitespace.


```lua

local function byte_trim(s)
  vim.validate('s', s, 'string')
  local byte, sub = string.byte, string.sub
  local len = #s

  if len == 0 then return '' end

  if byte(s, 1) > 32 and byte(s, len) > 32 then return s end

  local start = 1
  while start <= len and byte(s, start) <= 32 do
    start = start + 1
  end

  if start > len then return '' end

  local stop = len
  while stop >= start and byte(s, stop) <= 32 do
    stop = stop - 1
  end

  return sub(s, start, stop)
end

local double_width_string = '　　　　　　　'

local byte_trim_string = byte_trim(double_width_string) -- returns '　　　　　　　'
local current_trim = vim.trim(double_width_string) -- returns ''
```
author_association: CONTRIBUTOR
user: login: monkoose
created_at: 2025-05-22T14:48:04Z
body: @lucario387 good catch.
Seems like a blocker for `string.byte` version. Maybe it can be adjusted? Are there many "double" whitespaces chars?
author_association: CONTRIBUTOR
user: login: monkoose
created_at: 2025-05-22T14:59:15Z
body: There is also
```lua
local trim5 = function(s)
  return (s:gsub('^%s+', ''):match('.*%S') or '')
end
```
Which is good for any input. But i'm not sure how lua/luajit optimizes this. Is there two allocations? Can gc be a problem for long strings?
author_association: CONTRIBUTOR
user: login: lucario387
created_at: 2025-05-22T15:00:16Z
body: > Maybe it can be adjusted? Are there many "double" whitespaces chars?

I'm very much unsure since for double-width whitespace in Japanese code yields `string.len("　") = 3`, and the first byte is `227`. Not sure about Chinese and Korean variants (if they do exist as separate codes). But then that means monkey patching for specific case that could've been covered by the lpeg pattern or double gsub version
author_association: CONTRIBUTOR
user: login: echasnovski
created_at: 2025-05-22T15:00:39Z
body: > @echasnovski Benchmarks are incomplete. And your version degrades (not that much so) with long non-whitespace strings (I think I have tested something similar, and because I wasn't aware of `shared.lua` limitations I had come up with that solution). Try to replace spaces in str1 to any char). And current `string.match()` is good for long non-whitespace strings.

Yes, indeed it does. This is easily fixable, though:

```lua
local trim4 = function(s)
  s = s:sub(1, 1):match('%s') and s:gsub('^%s+', '') or s
  s = s:sub(-1, -1):match('%s') and s:gsub('%s+$', '') or s
  return s
end
```

Benchmarks for previous cases are the same. Here are benchmarks for the string that contains the same number of `x` as the first "long" whitespace string:

```
Time: 0.003 ms -- current
Time: 0.015 ms -- lpeg
Time: 0.001 ms -- @glepnir's mega performant
Time: 0.001 ms -- two conditional gsub
```

**Edit**: seems to also be better than [this version](https://github.com/neovim/neovim/pull/34122#issuecomment-2901554643) on `str3` and "many x" strings. Usually having several non-anchored quantified patterns adds performance problems.
author_association: MEMBER
user: login: monkoose
created_at: 2025-05-22T15:12:29Z
body: @echasnovski 
> Yes, indeed it does. This is easily fixable, though:

And what if there are one space at each side? Still have the same issue of possible double allocations for long strings. Then gc could be a problem more than trim itself.
author_association: CONTRIBUTOR
user: login: echasnovski
created_at: 2025-05-22T15:21:29Z
body: > And what if there are one space at each side? Still have the same issue of possible double allocations for long strings. Then gc could be a problem more than trim itself.

I don't think this degree of performance optimization is needed here. There is an example of extreme degradation with current approach (wide whitespace only string), the "conditional gsub" approach fixes it. While at the same time being more performant than lpeg one for the wide string without leading or trailing spaces.

If there is benchmarking approach for the problem you describe, then we can find a better solution.
author_association: MEMBER
user: login: monkoose
created_at: 2025-05-22T15:29:25Z
body: > I don't think this degree of performance optimization is needed here. 

I do agree that this microseconds are pointless chase. 


author_association: CONTRIBUTOR
user: login: monkoose
created_at: 2025-05-22T18:18:01Z
body: @echasnovski I have updated benchmarks for all worst cases. Your implementation of gsub gsub degrade poorly for strings with big whitespace gaps in it.

```lua
local function benchmark(func, ...)
   func(...)
   local start = os.clock()
   func(...)
   local elapsed = os.clock() - start

   return string.format("%.3f ms", elapsed * 1000)
end

local funcs = {}

function funcs.match_trim(str)
   return str:match('^%s*(.*%S)') or ''
end

local trim_pattern = vim.re.compile("%s* {(%s* %S+)*}")
function funcs.lpeg_trim(s)
   return trim_pattern:match(s)
end

function funcs.gsub_gsub_trim(s)
   return (s:gsub('^%s+', ''):gsub('%s+$', ''))
end

function funcs.gsub_match_trim(s)
   return (s:gsub('^%s+', ''):match('.*%S') or '')
end

funcs.nitpicking_gsub_gsub = function(s)
  s = s:sub(1, 1):match('%s') and s:gsub('^%s+', '') or s
  s = s:sub(-1, -1):match('%s') and s:gsub('%s+$', '') or s
  return s
end

local strings = {}

strings.short = " \n \t hello \r \v"
strings.ten_thousand_white = "                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                "
strings.ten_thousand_chars = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
strings.ten_thousand_gaps = " a                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              a "
strings.ten_thousand_chars_with_spaces =  " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "

for k, v in pairs(funcs) do
   print(k .. ":")
   for ks, s in pairs(strings) do
      print("  " .. ks .. " - " .. benchmark(v, s))
   end
   print(" ")
end
```

For this improved benchmarks gsub_match is a clear winner. Not sure why in this results lpeg behave a little worse.
```
lpeg_trim:
  ten_thousand_gaps - 0.032 ms
  ten_thousand_white - 0.030 ms
  ten_thousand_chars_with_spaces - 0.031 ms
  short - 0.001 ms
  ten_thousand_chars - 0.030 ms

match_trim:
  ten_thousand_gaps - 0.006 ms
  ten_thousand_white - 280.662 ms
  ten_thousand_chars_with_spaces - 0.002 ms
  short - 0.001 ms
  ten_thousand_chars - 0.002 ms

gsub_gsub_trim:
  ten_thousand_gaps - 141.485 ms
  ten_thousand_white - 0.013 ms
  ten_thousand_chars_with_spaces - 0.051 ms
  short - 0.001 ms
  ten_thousand_chars - 0.050 ms

gsub_match_trim:
  ten_thousand_gaps - 0.002 ms
  ten_thousand_white - 0.013 ms
  ten_thousand_chars_with_spaces - 0.003 ms
  short - 0.001 ms
  ten_thousand_chars - 0.002 ms

nitpicking_gsub_gsub:
  ten_thousand_gaps - 142.876 ms
  ten_thousand_white - 0.014 ms
  ten_thousand_chars_with_spaces - 0.053 ms
  short - 0.001 ms
  ten_thousand_chars - 0.001 ms
```
author_association: CONTRIBUTOR
user: login: echasnovski
created_at: 2025-05-22T19:12:32Z
body: > @echasnovski I have updated benchmarks for all worst cases. Your implementation of gsub gsub degrade poorly for strings with big whitespace gaps in it.

Yeah, I can reproduce the same tendency of results. Nice find!

I also tested if this is indeed due to memory allocations for temporary string after `gsub()`, but it doesn't look like. The similar approach, but only with `:find()` shows similar performance.

The issue seems to be indeed the `'%s+$'` anchoring. Probably LuaJIT implementation has to do some backtracking which is costly in this case. Don't know.

Here is a bit more copy-paste-friendly version of the benchmarking code:

<details><summary>Code</summary>

```lua
-- Functions ------------------------------------------------------------------
local funcs = {}

function funcs.match_trim(str) return str:match('^%s*(.*%S)') or '' end

local trim_pattern = vim.re.compile('%s* {(%s* %S+)*}')
function funcs.lpeg_trim(s) return trim_pattern:match(s) end

function funcs.gsub_gsub_trim(s) return (s:gsub('^%s+', ''):gsub('%s+$', '')) end

function funcs.gsub_match_trim(s) return (s:gsub('^%s+', ''):match('.*%S') or '') end

function funcs.nitpicking_gsub_gsub(s)
  s = s:sub(1, 1):match('%s') and s:gsub('^%s+', '', 1) or s
  s = s:sub(-1, -1):match('%s') and s:gsub('%s+$', '', 1) or s
  return s
end

function funcs.find_sub(s)
  local _, from = s:find('^%s*')
  local to = s:find('%s*$')
  return s:sub(from + 1, to - 1)
end

local func_names = vim.tbl_keys(funcs)
table.sort(func_names)

-- Strings --------------------------------------------------------------------
local strings = {}

strings.short = ' \n \t hello \r \v'
strings.ten_thousand_white = string.rep(' ', 10000)
strings.ten_thousand_chars = string.rep('a', 10000)
strings.ten_thousand_gaps = ' a' .. string.rep(' ', 9998) .. 'a '
strings.ten_thousand_chars_with_spaces = ' ' .. string.rep('a', 10000) .. ' '

local string_names = vim.tbl_keys(strings)
table.sort(string_names)

-- Benchmark ------------------------------------------------------------------
local n = 10

local function benchmark(func, ...)
  func(...)
  local start = os.clock()
  for _ = 1, n do
    func(...)
  end
  local elapsed = (os.clock() - start) / n

  return string.format('%.3f ms', elapsed * 1000)
end

for _, f_name in ipairs(func_names) do
  local f = funcs[f_name]
  print(f_name .. ':')
  for _, s_name in ipairs(string_names) do
    print('  ' .. s_name .. ' - ' .. benchmark(f, strings[s_name]))
  end
  print(' ')
end
```

</details>

<details><summary>My output</summary>

```
find_sub:
  short - 0.001 ms
  ten_thousand_chars - 0.183 ms
  ten_thousand_chars_with_spaces - 0.196 ms
  ten_thousand_gaps - 274.004 ms
  ten_thousand_white - 0.058 ms

gsub_gsub_trim:
  short - 0.000 ms
  ten_thousand_chars - 0.076 ms
  ten_thousand_chars_with_spaces - 0.065 ms
  ten_thousand_gaps - 274.388 ms
  ten_thousand_white - 0.026 ms

gsub_match_trim:
  short - 0.000 ms
  ten_thousand_chars - 0.005 ms
  ten_thousand_chars_with_spaces - 0.003 ms
  ten_thousand_gaps - 0.003 ms
  ten_thousand_white - 0.026 ms

lpeg_trim:
  short - 0.000 ms
  ten_thousand_chars - 0.017 ms
  ten_thousand_chars_with_spaces - 0.017 ms
  ten_thousand_gaps - 0.014 ms
  ten_thousand_white - 0.014 ms

match_trim:
  short - 0.000 ms
  ten_thousand_chars - 0.003 ms
  ten_thousand_chars_with_spaces - 0.003 ms
  ten_thousand_gaps - 0.003 ms
  ten_thousand_white - 278.231 ms

nitpicking_gsub_gsub:
  short - 0.001 ms
  ten_thousand_chars - 0.000 ms
  ten_thousand_chars_with_spaces - 0.065 ms
  ten_thousand_gaps - 274.169 ms
  ten_thousand_white - 0.026 ms
```

</details>
author_association: MEMBER
user: login: monkoose
created_at: 2025-05-23T05:57:59Z
body: @lucario387
I have done manual testing of `test/functional/lua/vim_spec.lua`. You were right `assert` in the tests always true, because it checks only if first arg is truthy ( not nil ).
But at the same time you have confused me - pattern `%s` doesn't respect "IDEOGRAPHIC SPACE" char either. And current `vim.trim` doesn't trim it. So using loops and string.byte is viable solution and behaves the same as trimming with lua patterns `%s` and `%S`.
Maybe in modern UTF-8 era it should detect such chars, but it is out of scope of this implementation.

author_association: CONTRIBUTOR
user: login: lucario387
created_at: 2025-05-23T11:28:47Z
body: > But at the same time you have confused me - pattern %s doesn't respect "IDEOGRAPHIC SPACE" char either


I found the same issue too. On my linux setup the double width whitespace was consumed while today I tested on windows and nothing was trimmed, leading to the assert check weirdness. Will test again on linux later today.

Very sorry for the wrong callout.🙇
author_association: CONTRIBUTOR
user: login: echasnovski
created_at: 2025-05-23T11:45:12Z
body: > The issue seems to be indeed the `'%s+$'` anchoring. Probably LuaJIT implementation has to do some backtracking which is costly in this case. Don't know.

I was curious and did little digging. It is a known issue present both in LuaJIT and plain Lua: LuaJIT/LuaJIT#118. Probably won't be solved.

The `s:gsub('^%s+', ''):match('^.*%S') or ''` approach still seems to be the best here. Especially since it is documented to use 'Lua pattern "%s"' as the definition of whitespace, so taking "IDEOGRAPHIC SPACE" into account might be a bit extra here.
author_association: MEMBER
user: login: justinmk
created_at: 2025-05-23T14:06:08Z
body: > The `s:gsub('^%s+', ''):match('^.*%S') or ''` approach still seems to be the best here.

a 2-line change is welcome. a 30-line change is not, especially when the difference is not significant.
author_association: MEMBER
user: login: monkoose
created_at: 2025-05-23T14:36:23Z
body: @justinmk Is there any reason for this? There are much larger functions in `shared.lua`. If you have cheated and created one line function previously which could be really slow for some input, it is definitely hard to "change" it without not "adding" more lines.

If core team is fine with the `gsub`+`match` solution I can revert to it, but let me still remind that unnecessary allocation is not good too.

So I will wait for your final word. I don't mind any solution, because they are definitely much better than current one.
author_association: CONTRIBUTOR
user: login: justinmk
created_at: 2025-05-23T14:54:37Z
body: > Is there any reason for this? There are much larger functions in `shared.lua`

if those functions could be achieved with 80% less code at a 5% perf cost, then they wouldn't be like that.
author_association: MEMBER
user: login: monkoose
created_at: 2025-05-23T15:37:37Z
body: @echasnovski @justinmk my apology, `%s` is only 9,10,11,12,13 and 32 bytes. So vim.trim() shouldn't trim any other char below 32 byte and glipnir implementation was wrong from the start.
Reverting to `gsub`+`match`.
author_association: CONTRIBUTOR
user: login: lewis6991
created_at: 2025-05-23T17:20:12Z
body: I think the benchmarking code is probably worth including in `benchmark/`. And also a comment explaining why `vim.trim` is implemented the way it is.
author_association: MEMBER
user: login: monkoose
created_at: 2025-05-24T08:29:05Z
body: @lewis6991 I have added benchmark file. But how it is working? I don't see any of it in CI, is it only for local benchmarking?
Is it measured and cached results from release to release?

As of some comment: I have not the best English, so not sure if I want to add broken English into source code. And I'm not even sure what it should mention, but the branch is open for editing.
author_association: CONTRIBUTOR
user: login: lewis6991
created_at: 2025-05-24T09:37:11Z
body: yes at the moment it's just for local use. We don't run any of it in CI.
author_association: MEMBER