glamour 0.1.0-x86-linux-musl
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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +306 -0
- data/ext/glamour/extconf.rb +59 -0
- data/ext/glamour/extension.c +300 -0
- data/glamour.gemspec +34 -0
- data/go/build/linux_386/libglamour.a +0 -0
- data/go/build/linux_386/libglamour.h +91 -0
- data/go/glamour.go +160 -0
- data/go/go.mod +35 -0
- data/go/go.sum +69 -0
- data/lib/glamour/3.2/glamour.so +0 -0
- data/lib/glamour/3.3/glamour.so +0 -0
- data/lib/glamour/3.4/glamour.so +0 -0
- data/lib/glamour/renderer.rb +47 -0
- data/lib/glamour/style.rb +46 -0
- data/lib/glamour/style_definition.rb +39 -0
- data/lib/glamour/version.rb +8 -0
- data/lib/glamour.rb +76 -0
- metadata +67 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 60c6bf304b93c0f4872a1bd3c34add654fca411ec14a0b9f1c436e59966273fa
|
|
4
|
+
data.tar.gz: b0c1a3d50d6dd3da9b0bcd94f93866e25f463167a59e426ddea30ac02cdc98a9
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ac96f6ef88fe6c13e9a299088bfd3f331bbd7807b48f6541e2fb706c58cd68f4344759f279c20bf04582c53dd4f8f6a9150bbffe62a4fb5d1384b709ab732153
|
|
7
|
+
data.tar.gz: 6380877734ecf70704f0b53e42a1dd7af837b2758f94154b0a05630f32b91e2b49a5278150ad3996b04e249bb11d2924d36156ce887363408ff75e177bb1fec6
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Marco Roth
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>Glamour</h1>
|
|
3
|
+
<h4>Stylesheet-based Markdown Rendering for Ruby CLI Apps</h4>
|
|
4
|
+
|
|
5
|
+
<p>
|
|
6
|
+
<a href="https://rubygems.org/gems/glamour"><img alt="Gem Version" src="https://img.shields.io/gem/v/glamour"></a>
|
|
7
|
+
<a href="https://github.com/marcoroth/glamour-ruby/blob/main/LICENSE.txt"><img alt="License" src="https://img.shields.io/github/license/marcoroth/glamour-ruby"></a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p>Ruby bindings for <a href="https://github.com/charmbracelet/glamour">charmbracelet/glamour</a>.<br/>Render markdown documents with beautiful styling on ANSI-compatible terminals.</p>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
**Add to your Gemfile:**
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
gem "glamour"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Or install directly:**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
gem install glamour
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### Basic Rendering
|
|
30
|
+
|
|
31
|
+
**Render markdown with auto-detected style:**
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
require "glamour"
|
|
35
|
+
|
|
36
|
+
puts Glamour.render("# Hello World")
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Render with a specific style:**
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
puts Glamour.render("# Hello", style: "dark")
|
|
43
|
+
puts Glamour.render("# Hello", style: "light")
|
|
44
|
+
puts Glamour.render("# Hello", style: "dracula")
|
|
45
|
+
puts Glamour.render("# Hello", style: "notty")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Render with word wrap:**
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
puts Glamour.render(long_markdown, width: 80)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Render Options
|
|
55
|
+
|
|
56
|
+
| Option | Description |
|
|
57
|
+
|--------|-------------|
|
|
58
|
+
| `style` | `"auto"`, `"dark"`, `"light"`, `"notty"`, `"dracula"` |
|
|
59
|
+
| `width` | Word wrap width |
|
|
60
|
+
| `emoji` | Enable emoji rendering (`:wave:` → 👋) |
|
|
61
|
+
| `preserve_newlines` | Preserve newlines in output |
|
|
62
|
+
| `base_url` | Base URL for relative links |
|
|
63
|
+
| `color_profile` | `:auto`, `:true_color`, `:ansi256`, `:ansi`, `:ascii` |
|
|
64
|
+
|
|
65
|
+
**Example with all options:**
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
Glamour.render(markdown,
|
|
69
|
+
style: "dark",
|
|
70
|
+
width: 80,
|
|
71
|
+
emoji: true,
|
|
72
|
+
preserve_newlines: true,
|
|
73
|
+
base_url: "https://example.com",
|
|
74
|
+
color_profile: :true_color
|
|
75
|
+
)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Custom Styles with Hash
|
|
79
|
+
|
|
80
|
+
**Define a custom style:**
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
custom_style = {
|
|
84
|
+
heading: { bold: true, color: "212" },
|
|
85
|
+
strong: { bold: true, color: "196" },
|
|
86
|
+
emph: { italic: true, color: "226" },
|
|
87
|
+
code: { color: "203", background_color: "236" }
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Render with the custom style:**
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
Glamour.render_with_style("# Hello **World**", custom_style)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**With width option:**
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
Glamour.render_with_style("# Hello", custom_style, width: 60)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Style DSL
|
|
104
|
+
|
|
105
|
+
**Define reusable styles using a Ruby DSL:**
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
class MyStyle < Glamour::Style
|
|
109
|
+
style :heading do
|
|
110
|
+
bold true
|
|
111
|
+
color "212"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
style :h1 do
|
|
115
|
+
prefix "# "
|
|
116
|
+
color "99"
|
|
117
|
+
bold true
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
style :strong do
|
|
121
|
+
bold true
|
|
122
|
+
color "196"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
style :emph do
|
|
126
|
+
italic true
|
|
127
|
+
color "226"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
style :code do
|
|
131
|
+
color "203"
|
|
132
|
+
background_color "236"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
style :document do
|
|
136
|
+
margin 2
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Use the style class directly:**
|
|
142
|
+
|
|
143
|
+
```ruby
|
|
144
|
+
MyStyle.render("# Hello **World**")
|
|
145
|
+
MyStyle.render("# Hello", width: 80)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Or pass to Glamour.render:**
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
Glamour.render("# Hello", style: MyStyle)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Reusable Renderer
|
|
155
|
+
|
|
156
|
+
**Create a renderer with preset options:**
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
renderer = Glamour::Renderer.new(
|
|
160
|
+
style: "dark",
|
|
161
|
+
width: 80,
|
|
162
|
+
emoji: true
|
|
163
|
+
)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Render multiple documents:**
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
puts renderer.render("# Hello :wave:")
|
|
170
|
+
puts renderer.render("# Another document")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**With a Style class:**
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
renderer = Glamour::Renderer.new(style: MyStyle, width: 60)
|
|
177
|
+
puts renderer.render("# Styled output")
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Available Style Elements
|
|
181
|
+
|
|
182
|
+
### Block Elements
|
|
183
|
+
|
|
184
|
+
| Element | Description |
|
|
185
|
+
|---------|-------------|
|
|
186
|
+
| `document` | Root document wrapper |
|
|
187
|
+
| `paragraph` | Text paragraphs |
|
|
188
|
+
| `heading` | Base heading style (h1-h6 inherit from this) |
|
|
189
|
+
| `h1` - `h6` | Individual heading levels |
|
|
190
|
+
| `block_quote` | Block quotations |
|
|
191
|
+
| `code_block` | Fenced code blocks |
|
|
192
|
+
| `list` | List containers |
|
|
193
|
+
| `item` | List items (bullets) |
|
|
194
|
+
| `enumeration` | Numbered list items |
|
|
195
|
+
| `table` | Markdown tables |
|
|
196
|
+
| `hr` | Horizontal rules |
|
|
197
|
+
|
|
198
|
+
### Inline Elements
|
|
199
|
+
|
|
200
|
+
| Element | Description |
|
|
201
|
+
|---------|-------------|
|
|
202
|
+
| `text` | Base text styling |
|
|
203
|
+
| `strong` | Bold text (`**bold**`) |
|
|
204
|
+
| `emph` | Italic text (`*italic*`) |
|
|
205
|
+
| `strikethrough` | Strikethrough text |
|
|
206
|
+
| `code` | Inline code (`` `code` ``) |
|
|
207
|
+
| `link` | Link elements |
|
|
208
|
+
| `link_text` | Link text display |
|
|
209
|
+
| `image` | Image references |
|
|
210
|
+
|
|
211
|
+
## Style Properties
|
|
212
|
+
|
|
213
|
+
**Text decoration:**
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
bold true
|
|
217
|
+
italic true
|
|
218
|
+
underline true
|
|
219
|
+
crossed_out true
|
|
220
|
+
faint true
|
|
221
|
+
inverse true
|
|
222
|
+
overlined true
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Colors (ANSI 256 color codes):**
|
|
226
|
+
|
|
227
|
+
```ruby
|
|
228
|
+
color "212"
|
|
229
|
+
background_color "236"
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Spacing:**
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
margin 2
|
|
236
|
+
indent 1
|
|
237
|
+
indent_token " "
|
|
238
|
+
level_indent 2
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Prefix/suffix:**
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
prefix "# "
|
|
245
|
+
suffix ""
|
|
246
|
+
block_prefix ""
|
|
247
|
+
block_suffix "\n"
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Built-in Styles
|
|
251
|
+
|
|
252
|
+
- `"auto"` - Auto-detect dark/light terminal
|
|
253
|
+
- `"dark"` - Dark terminal theme
|
|
254
|
+
- `"light"` - Light terminal theme
|
|
255
|
+
- `"notty"` - No colors (for non-TTY output)
|
|
256
|
+
- `"dracula"` - Dracula color scheme
|
|
257
|
+
|
|
258
|
+
## Version Info
|
|
259
|
+
|
|
260
|
+
```ruby
|
|
261
|
+
puts Glamour.version
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Development
|
|
265
|
+
|
|
266
|
+
**Requirements:**
|
|
267
|
+
- Go 1.23+
|
|
268
|
+
- Ruby 3.2+
|
|
269
|
+
|
|
270
|
+
**Install dependencies:**
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
bundle install
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Build the Go library and compile the extension:**
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
bundle exec rake compile
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Run tests:**
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
bundle exec rake test
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Run demos:**
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
./demo/basic
|
|
292
|
+
./demo/styles
|
|
293
|
+
./demo/style_dsl
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Contributing
|
|
297
|
+
|
|
298
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/marcoroth/glamour-ruby.
|
|
299
|
+
|
|
300
|
+
## License
|
|
301
|
+
|
|
302
|
+
The gem is available as open source under the terms of the MIT License.
|
|
303
|
+
|
|
304
|
+
## Acknowledgments
|
|
305
|
+
|
|
306
|
+
This gem wraps [charmbracelet/glamour](https://github.com/charmbracelet/glamour), part of the excellent [Charm](https://charm.sh) ecosystem.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "mkmf"
|
|
4
|
+
|
|
5
|
+
extension_name = "glamour"
|
|
6
|
+
|
|
7
|
+
def detect_platform
|
|
8
|
+
cpu = RbConfig::CONFIG["host_cpu"]
|
|
9
|
+
os = RbConfig::CONFIG["host_os"]
|
|
10
|
+
|
|
11
|
+
arch = case cpu
|
|
12
|
+
when /aarch64|arm64/ then "arm64"
|
|
13
|
+
when /x86_64|amd64/ then "amd64"
|
|
14
|
+
when /arm/ then "arm"
|
|
15
|
+
when /i[3-6]86/ then "386"
|
|
16
|
+
else cpu
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
goos = case os
|
|
20
|
+
when /darwin/ then "darwin"
|
|
21
|
+
when /mswin|mingw/ then "windows"
|
|
22
|
+
else "linux"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
"#{goos}_#{arch}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
platform = detect_platform
|
|
29
|
+
go_lib_dir = File.expand_path("../../go/build/#{platform}", __dir__)
|
|
30
|
+
|
|
31
|
+
puts "Looking for Go library in: #{go_lib_dir}"
|
|
32
|
+
|
|
33
|
+
unless File.exist?(File.join(go_lib_dir, "libglamour.a"))
|
|
34
|
+
abort <<~ERROR
|
|
35
|
+
Could not find libglamour.a for platform #{platform}
|
|
36
|
+
|
|
37
|
+
Please build the Go archive first:
|
|
38
|
+
cd go && go build -buildmode=c-archive -o build/#{platform}/libglamour.a .
|
|
39
|
+
|
|
40
|
+
Or run:
|
|
41
|
+
bundle exec rake go:build
|
|
42
|
+
ERROR
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
$LDFLAGS << " -L#{go_lib_dir}"
|
|
46
|
+
$INCFLAGS << " -I#{go_lib_dir}"
|
|
47
|
+
|
|
48
|
+
$LOCAL_LIBS << " #{go_lib_dir}/libglamour.a"
|
|
49
|
+
|
|
50
|
+
case RbConfig::CONFIG["host_os"]
|
|
51
|
+
when /darwin/
|
|
52
|
+
$LDFLAGS << " -framework CoreFoundation -framework Security -framework SystemConfiguration"
|
|
53
|
+
$LDFLAGS << " -lresolv"
|
|
54
|
+
when /linux/
|
|
55
|
+
$LDFLAGS << " -lpthread -lm -ldl"
|
|
56
|
+
$LDFLAGS << " -lresolv" if find_library("resolv", "res_query")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
create_makefile("#{extension_name}/#{extension_name}")
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/* frozen_string_literal: true */
|
|
2
|
+
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
#include "libglamour.h"
|
|
5
|
+
|
|
6
|
+
VALUE mGlamour;
|
|
7
|
+
VALUE cRenderer;
|
|
8
|
+
|
|
9
|
+
#define COLOR_PROFILE_AUTO 0
|
|
10
|
+
#define COLOR_PROFILE_TRUE_COLOR 1
|
|
11
|
+
#define COLOR_PROFILE_ANSI256 2
|
|
12
|
+
#define COLOR_PROFILE_ANSI 3
|
|
13
|
+
#define COLOR_PROFILE_ASCII 4
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* Render markdown to terminal-styled output.
|
|
17
|
+
*
|
|
18
|
+
* @param markdown [String] The markdown content to render
|
|
19
|
+
* @param style [String] Style name: "auto", "dark", "light", "notty", "dracula"
|
|
20
|
+
* @param width [Integer] Optional word wrap width
|
|
21
|
+
* @param emoji [Boolean] Enable emoji rendering
|
|
22
|
+
* @param preserve_newlines [Boolean] Preserve newlines in output
|
|
23
|
+
* @param base_url [String] Base URL for relative links
|
|
24
|
+
* @param color_profile [Symbol] Color profile: :auto, :true_color, :ansi256, :ansi, :ascii
|
|
25
|
+
* @return [String] Rendered output with ANSI escape codes
|
|
26
|
+
*/
|
|
27
|
+
static VALUE glamour_render_rb(int argc, VALUE *argv, VALUE self) {
|
|
28
|
+
VALUE markdown, options;
|
|
29
|
+
rb_scan_args(argc, argv, "1:", &markdown, &options);
|
|
30
|
+
|
|
31
|
+
Check_Type(markdown, T_STRING);
|
|
32
|
+
|
|
33
|
+
const char *style = "auto";
|
|
34
|
+
const char *base_url = NULL;
|
|
35
|
+
|
|
36
|
+
int width = 0;
|
|
37
|
+
int emoji = 0;
|
|
38
|
+
int preserve_newlines = 0;
|
|
39
|
+
int color_profile = COLOR_PROFILE_AUTO;
|
|
40
|
+
int has_advanced_options = 0;
|
|
41
|
+
|
|
42
|
+
if (!NIL_P(options)) {
|
|
43
|
+
VALUE style_value = rb_hash_lookup(options, ID2SYM(rb_intern("style")));
|
|
44
|
+
VALUE width_value = rb_hash_lookup(options, ID2SYM(rb_intern("width")));
|
|
45
|
+
VALUE emoji_value = rb_hash_lookup(options, ID2SYM(rb_intern("emoji")));
|
|
46
|
+
VALUE color_value = rb_hash_lookup(options, ID2SYM(rb_intern("color_profile")));
|
|
47
|
+
|
|
48
|
+
VALUE base_url_value = rb_hash_lookup(options, ID2SYM(rb_intern("base_url")));
|
|
49
|
+
VALUE preserve_value = rb_hash_lookup(options, ID2SYM(rb_intern("preserve_newlines")));
|
|
50
|
+
|
|
51
|
+
if (!NIL_P(style_value)) {
|
|
52
|
+
Check_Type(style_value, T_STRING);
|
|
53
|
+
style = StringValueCStr(style_value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!NIL_P(width_value)) {
|
|
57
|
+
width = NUM2INT(width_value);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (RTEST(emoji_value)) {
|
|
61
|
+
emoji = 1;
|
|
62
|
+
has_advanced_options = 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (RTEST(preserve_value)) {
|
|
66
|
+
preserve_newlines = 1;
|
|
67
|
+
has_advanced_options = 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!NIL_P(base_url_value)) {
|
|
71
|
+
Check_Type(base_url_value, T_STRING);
|
|
72
|
+
base_url = StringValueCStr(base_url_value);
|
|
73
|
+
has_advanced_options = 1;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!NIL_P(color_value)) {
|
|
77
|
+
has_advanced_options = 1;
|
|
78
|
+
|
|
79
|
+
if (color_value == ID2SYM(rb_intern("true_color"))) {
|
|
80
|
+
color_profile = COLOR_PROFILE_TRUE_COLOR;
|
|
81
|
+
} else if (color_value == ID2SYM(rb_intern("ansi256"))) {
|
|
82
|
+
color_profile = COLOR_PROFILE_ANSI256;
|
|
83
|
+
} else if (color_value == ID2SYM(rb_intern("ansi"))) {
|
|
84
|
+
color_profile = COLOR_PROFILE_ANSI;
|
|
85
|
+
} else if (color_value == ID2SYM(rb_intern("ascii"))) {
|
|
86
|
+
color_profile = COLOR_PROFILE_ASCII;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
char *result;
|
|
92
|
+
|
|
93
|
+
if (has_advanced_options || width > 0) {
|
|
94
|
+
result = glamour_render_with_options(
|
|
95
|
+
(char *) StringValueCStr(markdown),
|
|
96
|
+
(char *) style,
|
|
97
|
+
width,
|
|
98
|
+
emoji,
|
|
99
|
+
preserve_newlines,
|
|
100
|
+
(char *) base_url,
|
|
101
|
+
color_profile
|
|
102
|
+
);
|
|
103
|
+
} else {
|
|
104
|
+
result = glamour_render(
|
|
105
|
+
(char *) StringValueCStr(markdown),
|
|
106
|
+
(char *) style
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
VALUE rb_result = rb_utf8_str_new_cstr(result);
|
|
111
|
+
glamour_free(result);
|
|
112
|
+
|
|
113
|
+
return rb_result;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/*
|
|
117
|
+
* Render markdown with a custom JSON style.
|
|
118
|
+
*
|
|
119
|
+
* @param markdown [String] The markdown content to render
|
|
120
|
+
* @param json_style [String] JSON style definition
|
|
121
|
+
* @param width [Integer] Optional word wrap width
|
|
122
|
+
* @return [String] Rendered output with ANSI escape codes
|
|
123
|
+
*/
|
|
124
|
+
static VALUE glamour_render_with_json_rb(int argc, VALUE *argv, VALUE self) {
|
|
125
|
+
VALUE markdown, json_style, options;
|
|
126
|
+
rb_scan_args(argc, argv, "2:", &markdown, &json_style, &options);
|
|
127
|
+
|
|
128
|
+
Check_Type(markdown, T_STRING);
|
|
129
|
+
Check_Type(json_style, T_STRING);
|
|
130
|
+
|
|
131
|
+
int width = 0;
|
|
132
|
+
|
|
133
|
+
if (!NIL_P(options)) {
|
|
134
|
+
VALUE width_value = rb_hash_lookup(options, ID2SYM(rb_intern("width")));
|
|
135
|
+
|
|
136
|
+
if (!NIL_P(width_value)) {
|
|
137
|
+
width = NUM2INT(width_value);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
char *result = glamour_render_with_json_style(
|
|
142
|
+
(char *) StringValueCStr(markdown),
|
|
143
|
+
(char *) StringValueCStr(json_style),
|
|
144
|
+
width
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
VALUE rb_result = rb_utf8_str_new_cstr(result);
|
|
148
|
+
glamour_free(result);
|
|
149
|
+
|
|
150
|
+
return rb_result;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/*
|
|
154
|
+
* Get the upstream glamour version.
|
|
155
|
+
*
|
|
156
|
+
* @return [String] Upstream glamour version
|
|
157
|
+
*/
|
|
158
|
+
static VALUE glamour_upstream_version_rb(VALUE self) {
|
|
159
|
+
char *version = glamour_upstream_version();
|
|
160
|
+
VALUE rb_version = rb_utf8_str_new_cstr(version);
|
|
161
|
+
glamour_free(version);
|
|
162
|
+
|
|
163
|
+
return rb_version;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/*
|
|
167
|
+
* Get the glamour version info.
|
|
168
|
+
*
|
|
169
|
+
* @return [String] Version information string
|
|
170
|
+
*/
|
|
171
|
+
static VALUE glamour_version_rb(VALUE self) {
|
|
172
|
+
VALUE gem_version = rb_const_get(self, rb_intern("VERSION"));
|
|
173
|
+
VALUE upstream_version = glamour_upstream_version_rb(self);
|
|
174
|
+
VALUE format_string = rb_utf8_str_new_cstr("glamour v%s (upstream v%s) [Go native extension]");
|
|
175
|
+
|
|
176
|
+
return rb_funcall(rb_mKernel, rb_intern("sprintf"), 3, format_string, gem_version, upstream_version);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* Renderer class methods */
|
|
180
|
+
|
|
181
|
+
static VALUE renderer_alloc(VALUE klass) {
|
|
182
|
+
return Data_Wrap_Struct(klass, NULL, NULL, NULL);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
static VALUE renderer_initialize(int argc, VALUE *argv, VALUE self) {
|
|
186
|
+
VALUE options;
|
|
187
|
+
rb_scan_args(argc, argv, "0:", &options);
|
|
188
|
+
|
|
189
|
+
rb_iv_set(self, "@style", rb_str_new_cstr("auto"));
|
|
190
|
+
rb_iv_set(self, "@width", INT2FIX(0));
|
|
191
|
+
rb_iv_set(self, "@emoji", Qfalse);
|
|
192
|
+
rb_iv_set(self, "@preserve_newlines", Qfalse);
|
|
193
|
+
rb_iv_set(self, "@base_url", Qnil);
|
|
194
|
+
rb_iv_set(self, "@color_profile", ID2SYM(rb_intern("auto")));
|
|
195
|
+
rb_iv_set(self, "@json_style", Qnil);
|
|
196
|
+
|
|
197
|
+
if (!NIL_P(options)) {
|
|
198
|
+
VALUE style = rb_hash_lookup(options, ID2SYM(rb_intern("style")));
|
|
199
|
+
if (!NIL_P(style)) rb_iv_set(self, "@style", style);
|
|
200
|
+
|
|
201
|
+
VALUE width = rb_hash_lookup(options, ID2SYM(rb_intern("width")));
|
|
202
|
+
if (!NIL_P(width)) rb_iv_set(self, "@width", width);
|
|
203
|
+
|
|
204
|
+
VALUE emoji = rb_hash_lookup(options, ID2SYM(rb_intern("emoji")));
|
|
205
|
+
if (RTEST(emoji)) rb_iv_set(self, "@emoji", Qtrue);
|
|
206
|
+
|
|
207
|
+
VALUE preserve = rb_hash_lookup(options, ID2SYM(rb_intern("preserve_newlines")));
|
|
208
|
+
if (RTEST(preserve)) rb_iv_set(self, "@preserve_newlines", Qtrue);
|
|
209
|
+
|
|
210
|
+
VALUE base_url = rb_hash_lookup(options, ID2SYM(rb_intern("base_url")));
|
|
211
|
+
if (!NIL_P(base_url)) rb_iv_set(self, "@base_url", base_url);
|
|
212
|
+
|
|
213
|
+
VALUE color = rb_hash_lookup(options, ID2SYM(rb_intern("color_profile")));
|
|
214
|
+
if (!NIL_P(color)) rb_iv_set(self, "@color_profile", color);
|
|
215
|
+
|
|
216
|
+
VALUE json = rb_hash_lookup(options, ID2SYM(rb_intern("json_style")));
|
|
217
|
+
if (!NIL_P(json)) rb_iv_set(self, "@json_style", json);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return self;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
static VALUE renderer_render(VALUE self, VALUE markdown) {
|
|
224
|
+
Check_Type(markdown, T_STRING);
|
|
225
|
+
|
|
226
|
+
VALUE json_style = rb_iv_get(self, "@json_style");
|
|
227
|
+
|
|
228
|
+
if (!NIL_P(json_style)) {
|
|
229
|
+
int width = NUM2INT(rb_iv_get(self, "@width"));
|
|
230
|
+
|
|
231
|
+
char *result = glamour_render_with_json_style(
|
|
232
|
+
(char *)StringValueCStr(markdown),
|
|
233
|
+
(char *)StringValueCStr(json_style),
|
|
234
|
+
width
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
VALUE rb_result = rb_utf8_str_new_cstr(result);
|
|
238
|
+
glamour_free(result);
|
|
239
|
+
return rb_result;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
VALUE style_value = rb_iv_get(self, "@style");
|
|
243
|
+
const char *style = NIL_P(style_value) ? "auto" : StringValueCStr(style_value);
|
|
244
|
+
int width = NUM2INT(rb_iv_get(self, "@width"));
|
|
245
|
+
int emoji = RTEST(rb_iv_get(self, "@emoji")) ? 1 : 0;
|
|
246
|
+
int preserve_newlines = RTEST(rb_iv_get(self, "@preserve_newlines")) ? 1 : 0;
|
|
247
|
+
|
|
248
|
+
VALUE base_url_value = rb_iv_get(self, "@base_url");
|
|
249
|
+
const char *base_url = NIL_P(base_url_value) ? NULL : StringValueCStr(base_url_value);
|
|
250
|
+
|
|
251
|
+
VALUE color_value = rb_iv_get(self, "@color_profile");
|
|
252
|
+
int color_profile = COLOR_PROFILE_AUTO;
|
|
253
|
+
|
|
254
|
+
if (color_value == ID2SYM(rb_intern("true_color"))) {
|
|
255
|
+
color_profile = COLOR_PROFILE_TRUE_COLOR;
|
|
256
|
+
} else if (color_value == ID2SYM(rb_intern("ansi256"))) {
|
|
257
|
+
color_profile = COLOR_PROFILE_ANSI256;
|
|
258
|
+
} else if (color_value == ID2SYM(rb_intern("ansi"))) {
|
|
259
|
+
color_profile = COLOR_PROFILE_ANSI;
|
|
260
|
+
} else if (color_value == ID2SYM(rb_intern("ascii"))) {
|
|
261
|
+
color_profile = COLOR_PROFILE_ASCII;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
char *result = glamour_render_with_options(
|
|
265
|
+
(char *)StringValueCStr(markdown),
|
|
266
|
+
(char *)style,
|
|
267
|
+
width,
|
|
268
|
+
emoji,
|
|
269
|
+
preserve_newlines,
|
|
270
|
+
(char *)base_url,
|
|
271
|
+
color_profile
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
VALUE rb_result = rb_utf8_str_new_cstr(result);
|
|
275
|
+
glamour_free(result);
|
|
276
|
+
|
|
277
|
+
return rb_result;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
__attribute__((__visibility__("default"))) void Init_glamour(void) {
|
|
281
|
+
mGlamour = rb_define_module("Glamour");
|
|
282
|
+
|
|
283
|
+
rb_define_singleton_method(mGlamour, "render", glamour_render_rb, -1);
|
|
284
|
+
rb_define_singleton_method(mGlamour, "render_with_json", glamour_render_with_json_rb, -1);
|
|
285
|
+
rb_define_singleton_method(mGlamour, "upstream_version", glamour_upstream_version_rb, 0);
|
|
286
|
+
rb_define_singleton_method(mGlamour, "version", glamour_version_rb, 0);
|
|
287
|
+
|
|
288
|
+
cRenderer = rb_define_class_under(mGlamour, "Renderer", rb_cObject);
|
|
289
|
+
rb_define_alloc_func(cRenderer, renderer_alloc);
|
|
290
|
+
rb_define_method(cRenderer, "initialize", renderer_initialize, -1);
|
|
291
|
+
rb_define_method(cRenderer, "render", renderer_render, 1);
|
|
292
|
+
|
|
293
|
+
rb_define_attr(cRenderer, "style", 1, 1);
|
|
294
|
+
rb_define_attr(cRenderer, "width", 1, 1);
|
|
295
|
+
rb_define_attr(cRenderer, "emoji", 1, 1);
|
|
296
|
+
rb_define_attr(cRenderer, "preserve_newlines", 1, 1);
|
|
297
|
+
rb_define_attr(cRenderer, "base_url", 1, 1);
|
|
298
|
+
rb_define_attr(cRenderer, "color_profile", 1, 1);
|
|
299
|
+
rb_define_attr(cRenderer, "json_style", 1, 1);
|
|
300
|
+
}
|