gloo 6.5.1 → 6.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19bd707a24eb9bbd3e2759cdb2ae244d2dafc28f40c0f4046c856152e343261c
4
- data.tar.gz: fd3fd34b664abb32a464d3745de0ede24e136f2b2a7f375809170312bbec51a1
3
+ metadata.gz: 24b089e57c145daea09ee59a1967bc38ec4482d0a9a137f9e3a32e8b71fb4ece
4
+ data.tar.gz: 625b347a0ff732f2fe81008c9e7e6d56de92f84ef846ccd37ebeda10948117ab
5
5
  SHA512:
6
- metadata.gz: f21efa7866b7eeb455fb4e7a8c64465bcd41a498d6129f04220c69eb814178f92775aeb96ef0e2a972f6df481d4603acf6e3de7c728e6508262347012cfb20cc
7
- data.tar.gz: 956306465a135039e185104bb81cf504af379265814b5a02ba4637c3a6412463ce655aa48bae66e1f3315fd8c90925899c2ca0afda9fbf6a795c66b35e339967
6
+ metadata.gz: 3080060d8fea38b00cc1870d9ae07d8149db13395834d72a20c9f18f7b9c43d97b6af97177d653b7eaeeffa49b04f9005a8318f7aaaa56edf65619645dde8016
7
+ data.tar.gz: f137b40bf30a08e7af993fdd67041084a7f6aefbaf461934f1b4b8bd370e399cf3044537388d1a09be6dd954d73c3487ceddf6c977493287e3aa5ec6894f2b13
data/docs/application.md CHANGED
@@ -88,6 +88,8 @@ gloo:
88
88
  #
89
89
  # Run this script when starting up gloo.
90
90
  # (Only if a script file is not specified.)
91
+ # A bare filename (no path) is looked up in the config directory
92
+ # above. Either way, the .gloo extension is assumed if left off.
91
93
  #
92
94
  start_with:
93
95
 
data/lib/VERSION CHANGED
@@ -1 +1 @@
1
- 6.5.1
1
+ 6.6.0
data/lib/VERSION_NOTES CHANGED
@@ -1,3 +1,9 @@
1
+ 6.6.0 - 2026.09.12
2
+ - Allow shortcut reference for start file in configuration directory.
3
+ - Adds word wrap message for strings and text.
4
+ - Adds line wrapping for object comments and help documentation.
5
+
6
+
1
7
  6.5.1 - 2026.09.11
2
8
  - Adds doc to the load verb for recent changes.
3
9
 
@@ -207,7 +207,9 @@ module Gloo
207
207
  end
208
208
 
209
209
  name = @settings.start_with
210
- @persist_man.load( name ) if name
210
+ return if name.blank?
211
+
212
+ @persist_man.load( resolve_start_with( name ) )
211
213
  end
212
214
 
213
215
  #
@@ -382,6 +384,20 @@ module Gloo
382
384
 
383
385
  private
384
386
 
387
+ #
388
+ # Resolve the start_with setting to a loadable name/path.
389
+ # A bare filename (no directory separator) is resolved against
390
+ # the config directory rather than the project path, and the
391
+ # .gloo extension is assumed when not given.
392
+ #
393
+ def resolve_start_with( name )
394
+ ext = @persist_man.file_ext
395
+ name = "#{name}#{ext}" unless name.end_with?( ext )
396
+ return name if name.include?( File::SEPARATOR )
397
+
398
+ return File.join( @settings.config_path, name )
399
+ end
400
+
385
401
  #
386
402
  # Get the stack trace as a string, truncating the middle if it's long.
387
403
  #
@@ -189,13 +189,53 @@ module Gloo
189
189
  def get_default_settings
190
190
  projects = File.join( @user_root, 'projects' )
191
191
  str = <<~TEXT
192
+ #
193
+ # Gloo configuration
194
+ #
192
195
  gloo:
196
+
197
+ #
198
+ # Root directory for projects.
199
+ # Update this with the directory with your gloo projects.
200
+ #
193
201
  project_path: #{projects}
202
+
203
+ #
204
+ # Run this script when starting up gloo.
205
+ # (Only if a script file is not specified.)
206
+ # A bare filename (no path) is looked up in the config directory
207
+ # above. Either way, the .gloo extension is assumed if left off.
208
+ #
194
209
  start_with:
210
+
211
+ #
212
+ # Indentation (spaces) when showing an object outline.
213
+ #
195
214
  list_indent: 2
215
+
216
+ #
217
+ # Show listing the object tree,
218
+ # how many levels of children will be shown?
219
+ # Children at deeper levels will be hidden.
220
+ #
196
221
  list_levels: 3
222
+
223
+ #
224
+ # When listing the object tree, also show each object's doc (the
225
+ # comment declared immediately above it in its source file), if it
226
+ # has one.
227
+ #
197
228
  list_docs: false
229
+
230
+ #
231
+ # Show debug statements in the log?
232
+ #
198
233
  debug: false
234
+
235
+ #
236
+ # Color theme for console output: dark or light.
237
+ # Match this to your terminal's background.
238
+ #
199
239
  theme: #{DEFAULT_THEME}
200
240
  TEXT
201
241
  return str
@@ -24,6 +24,10 @@ module Gloo
24
24
  README_GLOB = 'README*'.freeze
25
25
  NO_README_YET = 'No README found for library'.freeze
26
26
 
27
+ # Matches a (possibly indented) markdown bullet line, capturing
28
+ # its leading whitespace and the text after '- '.
29
+ BULLET_RE = /\A(\s*)-\s+(.*)\z/.freeze
30
+
27
31
  #
28
32
  # Initialize the help shell for the given engine.
29
33
  #
@@ -249,10 +253,51 @@ module Gloo
249
253
  #
250
254
  def page_markdown( md )
251
255
  rule = '-' * @engine.platform.cols
252
- bracketed = "#{rule}\n#{md.strip}\n#{rule}\n"
256
+ wrapped = wrap_markdown_for_terminal( md.strip )
257
+ bracketed = "#{rule}\n#{wrapped}\n#{rule}\n"
253
258
  @engine.platform.page( Gloo::Docs::MarkdownRenderer.colorize( bracketed, @engine.theme ) )
254
259
  end
255
260
 
261
+ #
262
+ # Word-wrap plain (pre-color) markdown to the terminal width.
263
+ # Headings and fenced code blocks are left untouched (code is
264
+ # never rewrapped); a bullet line's continuation lines are
265
+ # indented to line up under its text, not under the '-' itself
266
+ # -- same convention as List#show_doc's doc-line wrapping.
267
+ #
268
+ def wrap_markdown_for_terminal( md )
269
+ width = Gloo::App::Settings.cols( @engine )
270
+ in_code_fence = false
271
+ lines = md.split( "\n", -1 ).flat_map do |line|
272
+ if line.strip.start_with?( '```' )
273
+ in_code_fence = !in_code_fence
274
+ next [ line ]
275
+ end
276
+ next [ line ] if in_code_fence || line.start_with?( '#' ) || line.strip.empty?
277
+
278
+ wrap_markdown_line( line, width )
279
+ end
280
+ return lines.join( "\n" )
281
+ end
282
+
283
+ #
284
+ # Wrap one prose or bullet markdown line to width. A bullet's
285
+ # continuation lines get a blank-space prefix the same length as
286
+ # its '{indent}- ', so wrapped text lines up under the bullet's
287
+ # own text.
288
+ #
289
+ def wrap_markdown_line( line, width )
290
+ match = BULLET_RE.match( line )
291
+ prefix = match ? "#{match[1]}- " : ''
292
+ text = match ? match[2] : line
293
+ cont_indent = ' ' * prefix.length
294
+
295
+ wrapped = Gloo::Objs::WordWrap.wrap( text, width - prefix.length )
296
+ # "".split( "\n", -1 ) is [], not [ '' ] -- keep a blank line as one piece.
297
+ pieces = wrapped.empty? ? [ '' ] : wrapped.split( "\n", -1 )
298
+ return pieces.each_with_index.map { |piece, i| "#{i.zero? ? prefix : cont_indent}#{piece}" }
299
+ end
300
+
256
301
  #
257
302
  # Snapshot the verb, object type, doc page, and loaded library
258
303
  # names for tab-completion.
@@ -55,6 +55,7 @@ module Gloo
55
55
  'splitl ({index}) — Get the substring to the left of index {index} (same as split (0, {index})). A parameter is required. Does not change the value of the string. It will have the substring.',
56
56
  'splitr ({index}) — Get the substring from index {index} to the end of the string (same as split ({index}, size)). A parameter is required. Does not change the value of the string. It will have the substring.',
57
57
  'split_list ({delim} {dst.path}) — Split the string by {delim} and put the parts into children of the container at {dst.path} (or an alias that points to one), one part per child, in order. Existing children are matched by position and have their values set; extra parts get new (untyped) children, numbered from 1; extra existing children are left alone. Both parameters are required. Does not change the value of the string. It will have the number of parts.',
58
+ 'word_wrap ({width}) — Word-wrap the string to {width} columns, breaking on whitespace (never mid-word; an overlong word is left on its own line rather than broken). The {width} parameter is optional; it defaults to the terminal\'s current width. This message changes the value of the string. It will have the wrapped string.',
58
59
  'page — Show the value in a pager (less), for viewing long content a screen at a time.'
59
60
  ]
60
61
  end
@@ -481,6 +482,25 @@ module Gloo
481
482
  return s
482
483
  end
483
484
 
485
+ #
486
+ # Word-wrap the string to the given column width, breaking on
487
+ # whitespace. Defaults to the terminal's current width when no
488
+ # width parameter is given.
489
+ #
490
+ def msg_word_wrap
491
+ width = Gloo::App::Settings.cols( @engine )
492
+ if @params&.token_count&.positive?
493
+ expr = Gloo::Expr::Expression.new( @engine, @params.tokens )
494
+ data = expr.evaluate
495
+ width = data.to_i
496
+ end
497
+
498
+ s = Gloo::Objs::WordWrap.wrap( value, width )
499
+ set_value s
500
+ @engine.heap.it.set_to s
501
+ return s
502
+ end
503
+
484
504
  #
485
505
  # Show the value in a pager, for long content.
486
506
  #
@@ -0,0 +1,58 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 2026 Eric Crane. All rights reserved.
3
+ #
4
+ # Word-wrapping utility.
5
+ # This is a static class.
6
+ #
7
+
8
+ module Gloo
9
+ module Objs
10
+ class WordWrap
11
+
12
+ # ---------------------------------------------------------------------
13
+ # Wrapping
14
+ # ---------------------------------------------------------------------
15
+
16
+ #
17
+ # Wrap the given text to the given column width.
18
+ # Greedy word-wrap: breaks on whitespace, never mid-word. A single
19
+ # word longer than the width is left on its own line rather than
20
+ # being hard-broken (e.g. a URL stays intact, just overflows).
21
+ # Existing line breaks in the text are preserved -- each line is
22
+ # wrapped independently, so blank lines and paragraph breaks survive.
23
+ #
24
+ def self.wrap( text, width )
25
+ return text.to_s if width.to_i <= 0
26
+
27
+ text.to_s.split( "\n", -1 ).map { |line| wrap_line( line, width ) }.join( "\n" )
28
+ end
29
+
30
+ # ---------------------------------------------------------------------
31
+ # Private
32
+ # ---------------------------------------------------------------------
33
+
34
+ #
35
+ # Wrap a single line (no embedded newlines) to the given width.
36
+ #
37
+ def self.wrap_line( line, width )
38
+ words = line.split( ' ' )
39
+ return line if words.empty?
40
+
41
+ lines = []
42
+ current = words.shift
43
+ words.each do |word|
44
+ if "#{current} #{word}".length > width
45
+ lines << current
46
+ current = word
47
+ else
48
+ current = "#{current} #{word}"
49
+ end
50
+ end
51
+ lines << current
52
+ return lines.join( "\n" )
53
+ end
54
+ private_class_method :wrap_line
55
+
56
+ end
57
+ end
58
+ end
@@ -92,21 +92,53 @@ module Gloo
92
92
 
93
93
  #
94
94
  # Show the object's doc (its leading comment, cleaned up) above
95
- # its listing line, one '#'-prefixed line per line of doc.
96
- # Silent when the object has none.
95
+ # its listing line, one '#'-prefixed line per line of doc, word-
96
+ # wrapped to fit the terminal. Silent when the object has none.
97
97
  #
98
98
  def show_doc( obj, indent )
99
99
  return if obj.doc.to_s.strip.empty?
100
100
 
101
- theme = @engine.theme
101
+ prefix = "#{indent}# "
102
+ cont_indent = "#{indent} " # lines up under the text after '# '
103
+ width = doc_wrap_width( prefix.length )
104
+
102
105
  # split( -1 ), not each_line -- a doc ending in a blank '#' line
103
106
  # ends with "\n", and each_line silently drops that trailing
104
107
  # empty line rather than yielding it.
105
108
  obj.doc.split( "\n", -1 ).each do |line|
106
- @engine.log.show theme.muted( "#{indent}# #{line}".rstrip )
109
+ show_doc_line( line, prefix, cont_indent, width )
107
110
  end
108
111
  end
109
112
 
113
+ #
114
+ # Word-wrap a single doc line to width, then show each wrapped
115
+ # piece: the '#' prefix on the first, the aligned continuation
116
+ # indent on the rest.
117
+ #
118
+ def show_doc_line( line, prefix, cont_indent, width )
119
+ theme = @engine.theme
120
+ wrapped = Gloo::Objs::WordWrap.wrap( line, width )
121
+ # "".split( "\n", -1 ) is [], not [ '' ] -- a blank line still
122
+ # needs one piece so it renders as a bare '#', not nothing.
123
+ pieces = wrapped.empty? ? [ '' ] : wrapped.split( "\n", -1 )
124
+ pieces.each_with_index do |piece, i|
125
+ p = i.zero? ? prefix : cont_indent
126
+ @engine.log.show theme.muted( "#{p}#{piece}".rstrip )
127
+ end
128
+ end
129
+
130
+ #
131
+ # How many columns of text fit after the doc-line prefix. Falls
132
+ # back to a small minimum rather than a zero/negative width when
133
+ # the terminal is very narrow or the indent is very deep.
134
+ #
135
+ def doc_wrap_width( prefix_length )
136
+ width = Gloo::App::Settings.cols( @engine ) - prefix_length
137
+ return width if width.positive?
138
+
139
+ return 20
140
+ end
141
+
110
142
  #
111
143
  # Determine how many levels to show.
112
144
  #
@@ -79,6 +79,23 @@ tests.objs.string [can] :
79
79
  eval it = 'three'
80
80
  assert "expected split (8 100) to clamp to 'three'"
81
81
 
82
+ word_wrap [test] :
83
+ description [string] : Word-wrap a string to an explicit width
84
+ on_test [script] :
85
+ put 'one two three four five' into ^^.s
86
+ tell ^^.s to word_wrap (10)
87
+ tell ^^.s to count_lines
88
+ eval it = 3
89
+ assert "expected word_wrap (10) to produce 3 lines"
90
+
91
+ word_wrap_keeps_long_word_intact [test] :
92
+ description [string] : word_wrap never breaks a word, even one wider than the width
93
+ on_test [script] :
94
+ put 'http://example.com/a-really-long-url short' into ^^.s
95
+ tell ^^.s to word_wrap (10)
96
+ check ^^.s for substring? ('http://example.com/a-really-long-url')
97
+ assert "expected the long word to remain intact on its own line"
98
+
82
99
  split_list [test] :
83
100
  description [string] : Split a string into children of a target container
84
101
  on_test [script] :
@@ -101,3 +101,12 @@ tests.objs.text [can] :
101
101
  put 'hello world' into ^^.b
102
102
  tell ^^.b to substring? ('lo w')
103
103
  assert "expected it to be true that it contains 'lo w'"
104
+
105
+ word_wrap [test] :
106
+ description [string] : Word-wrap text to an explicit width
107
+ on_test [script] :
108
+ put 'one two three four five' into ^^.b
109
+ tell ^^.b to word_wrap (10)
110
+ tell ^^.b to count_lines
111
+ eval it = 3
112
+ assert "expected word_wrap (10) to produce 3 lines"
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gloo
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.5.1
4
+ version: 6.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Crane
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-09-12 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: bundler
@@ -361,6 +362,7 @@ files:
361
362
  - lib/gloo/objs/basic/string_msgs.rb
362
363
  - lib/gloo/objs/basic/text.rb
363
364
  - lib/gloo/objs/basic/untyped.rb
365
+ - lib/gloo/objs/basic/word_wrap.rb
364
366
  - lib/gloo/objs/ctrl/each.rb
365
367
  - lib/gloo/objs/ctrl/each_child.rb
366
368
  - lib/gloo/objs/ctrl/each_dir.rb
@@ -505,6 +507,7 @@ licenses:
505
507
  - MIT
506
508
  metadata:
507
509
  documentation_uri: https://github.com/ecrane/gloo
510
+ post_install_message:
508
511
  rdoc_options: []
509
512
  require_paths:
510
513
  - lib
@@ -519,7 +522,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
519
522
  - !ruby/object:Gem::Version
520
523
  version: '0'
521
524
  requirements: []
522
- rubygems_version: 4.0.17
525
+ rubygems_version: 3.5.16
526
+ signing_key:
523
527
  specification_version: 4
524
528
  summary: Gloo scripting language. A scripting language built on ruby.
525
529
  test_files: []