yrby 0.7.1 → 0.8.1

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +88 -0
  3. data/Cargo.lock +3 -3
  4. data/README.md +593 -384
  5. data/ext/yrby/crates/html-core/Cargo.toml +1 -1
  6. data/ext/yrby/crates/html-core/src/lib.rs +13 -13
  7. data/ext/yrby/crates/lexical-html/Cargo.toml +2 -2
  8. data/ext/yrby/crates/lexical-html/src/lib.rs +90 -45
  9. data/ext/yrby/crates/prosemirror-html/Cargo.toml +2 -2
  10. data/ext/yrby/crates/prosemirror-html/src/lib.rs +44 -35
  11. data/ext/yrby/src/lib.rs +27 -12
  12. data/ext/yrby/src/protocol.rs +17 -17
  13. data/ext/yrby/src/read.rs +137 -26
  14. data/lib/generators/yrby/install/install_generator.rb +24 -13
  15. data/lib/generators/yrby/install/templates/document_channel.rb +4 -7
  16. data/lib/generators/yrby/tables/tables_generator.rb +7 -4
  17. data/lib/generators/yrby/tables/templates/create_y_tables.rb +1 -1
  18. data/lib/y/collaborative/attribute.rb +53 -0
  19. data/lib/y/collaborative/helper.rb +48 -0
  20. data/lib/y/collaborative.rb +98 -0
  21. data/lib/y/lexxy.rb +4 -4
  22. data/lib/y/rendering.rb +39 -15
  23. data/lib/y/tiptap.rb +3 -3
  24. data/lib/y/version.rb +1 -1
  25. metadata +4 -9
  26. data/ext/yrby/target/debug/build/clang-sys-e3ae45bd384f74c3/out/common.rs +0 -355
  27. data/ext/yrby/target/debug/build/clang-sys-e3ae45bd384f74c3/out/dynamic.rs +0 -276
  28. data/ext/yrby/target/debug/build/clang-sys-e3ae45bd384f74c3/out/macros.rs +0 -49
  29. data/ext/yrby/target/debug/build/rb-sys-4407948463231c4f/out/bindings-0.9.128-mri-arm64-darwin23-3.4.7.rs +0 -8934
  30. data/ext/yrby/target/debug/build/rb-sys-dbeea42737529c2d/out/bindings-0.9.128-mri-arm64-darwin23-3.4.7.rs +0 -8934
  31. data/ext/yrby/target/debug/build/serde-58ea0ee887cc2602/out/private.rs +0 -6
  32. data/ext/yrby/target/debug/build/serde_core-41f407c21c1f205e/out/private.rs +0 -5
  33. data/ext/yrby/target/debug/build/thiserror-0f1416a82ff26f22/out/private.rs +0 -5
data/lib/y/rendering.rb CHANGED
@@ -10,7 +10,7 @@ module Y
10
10
  # `marks:`. A rule is consulted before the built-in schema, so it can add a
11
11
  # custom node or override a built-in one.
12
12
  #
13
- # The usual way in is the block form — one `rules.node` call per type,
13
+ # The usual way in is the block form, one `rules.node` call per type,
14
14
  # keyword options for markup-as-data, a Ruby block for logic (see Builder
15
15
  # below). `contains:` says what's inside the node: :inline (formatted
16
16
  # text, the default), :blocks (child block nodes), or :none (a leaf). The
@@ -26,7 +26,7 @@ module Y
26
26
  # attrs: { "class" => ["callout callout--", :kind] },
27
27
  # contains: :blocks
28
28
  # end
29
- # `tag` is the element; `attrs` values are templates — a String literal,
29
+ # `tag` is the element; `attrs` values are templates: a String literal,
30
30
  # a Symbol referencing one of the node's stored attributes, or an Array
31
31
  # mixing both (an attribute that resolves empty is omitted); `text` is a
32
32
  # template for literal text content; `void: true` emits no closing tag;
@@ -45,20 +45,20 @@ module Y
45
45
  # document is locked) and receives a RenderRules::Node with the node's
46
46
  # type, stored attributes, children already rendered to HTML, and
47
47
  # child_types (its element/block children by type). Its return value is
48
- # spliced in verbatim — it is trusted HTML, so escape any attribute
48
+ # spliced in verbatim: it is trusted HTML, so escape any attribute
49
49
  # values you interpolate.
50
50
  #
51
51
  # Mark rules (ProseMirror only) are declarative: `tag` plus `attrs`
52
52
  # templates whose Symbol refs resolve against the mark's own attributes. A
53
53
  # custom mark wraps outside every built-in mark; several custom marks nest
54
54
  # alphabetically. A rule for a built-in mark's stored name replaces its
55
- # wrap (the markup changes, the semantics don't — an overridden code mark
55
+ # wrap (the markup changes, the semantics don't: an overridden code mark
56
56
  # still excludes the other formatting).
57
57
  module RenderRules
58
58
  # What a callback receives. `attrs` keys are as stored (Lexical's own
59
59
  # props keep their "__" prefix); `content` is the node's children,
60
60
  # already rendered to an HTML string; `child_types` lists the node's
61
- # element/block children by type, in document order — the structural
61
+ # element/block children by type, in document order: the structural
62
62
  # facts attrs and content can't answer (a gallery's image count, whether
63
63
  # a list item holds a nested list).
64
64
  Node = Data.define(:type, :attrs, :content, :child_types)
@@ -137,7 +137,7 @@ module Y
137
137
  # from stored values. Text content escapes `&`, `<`, `>` (quotes stay
138
138
  # literal, matching the browser serializer); attribute values also
139
139
  # escape `"`. Prefer these over ERB::Util.html_escape when byte parity
140
- # with editor output matters — html_escape also rewrites apostrophes.
140
+ # with editor output matters: html_escape also rewrites apostrophes.
141
141
  def escape_text(value)
142
142
  value.to_s.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
143
143
  end
@@ -212,10 +212,10 @@ module Y
212
212
  # they compile the rules config, hold the callbacks, and splice deferred
213
213
  # segments after a render. The native handle does everything else.
214
214
  class Lexical
215
- # `Y::Lexical.new(doc, nodes: { "type" => rule })` — see Y::RenderRules
215
+ # `Y::Lexical.new(doc, nodes: { "type" => rule })`; see Y::RenderRules
216
216
  # for the rule forms. This is core Lexical only: paragraphs, headings,
217
217
  # quotes, code, lists, tables, links, text formatting. Editor-specific
218
- # nodes arrive as rules — Y::Lexxy subclasses this with the Lexxy schema;
218
+ # nodes arrive as rules. Y::Lexxy subclasses this with the Lexxy schema;
219
219
  # a different Lexical editor brings its own rule set the same way.
220
220
  def initialize(doc, nodes: {})
221
221
  builder = RenderRules::Builder.new(marks_allowed: false)
@@ -232,23 +232,35 @@ module Y
232
232
  RenderRules.splice(result, @render_callbacks)
233
233
  end
234
234
 
235
- # What node types this document actually contains — the discovery aid
235
+ # What node types this document actually contains: the discovery aid
236
236
  # for writing rules. Facts per type: "count", "attrs" (names as stored),
237
237
  # "children" (child node types), "text" (whether it holds text runs),
238
- # and "handled" ("builtin", "rule", or nil — nil marks the types you
238
+ # and "handled" ("builtin", "rule", or nil; nil marks the types you
239
239
  # still need a rule for). Children plus text is how you pick contains:.
240
240
  def node_types(root = nil)
241
241
  json = root.nil? ? @native.node_types : @native.node_types(root)
242
242
  json && JSON.parse(json)
243
243
  end
244
+
245
+ # The node types to_html can't fully render: types in the document that
246
+ # neither the built-in schema nor a registered rule handles. An unknown
247
+ # container or inline wrapper renders its children without its own
248
+ # markup, so its text stays. An unknown decorator renders nothing, so
249
+ # content kept only in its attributes is missing from the HTML. Returns
250
+ # [] when every type is handled, and when the root is missing or isn't
251
+ # Lexical-shaped, because to_html returns nil there.
252
+ def unknown_types(root = nil)
253
+ types = node_types(root)
254
+ types ? types.filter_map { |type, info| type if info["handled"].nil? } : []
255
+ end
244
256
  end
245
257
 
246
258
  class ProseMirror
247
- # `Y::ProseMirror.new(doc, nodes: {...}, marks: {...})` — see
259
+ # `Y::ProseMirror.new(doc, nodes: {...}, marks: {...})`; see
248
260
  # Y::RenderRules for the rule forms. This is core ProseMirror only:
249
261
  # prosemirror-schema-basic plus the prosemirror-tables family, and the
250
- # full mark set (marks are native — see `rules.mark` for overrides).
251
- # Editor-specific nodes arrive as rules — Y::Tiptap subclasses this with
262
+ # full mark set (marks are native; see `rules.mark` for overrides).
263
+ # Editor-specific nodes arrive as rules. Y::Tiptap subclasses this with
252
264
  # Tiptap's extension nodes; a different ProseMirror editor brings its
253
265
  # own rule set the same way.
254
266
  def initialize(doc, nodes: {}, marks: {})
@@ -267,15 +279,27 @@ module Y
267
279
  RenderRules.splice(result, @render_callbacks)
268
280
  end
269
281
 
270
- # What node types this document actually contains — the discovery aid
282
+ # What node types this document actually contains: the discovery aid
271
283
  # for writing rules. Facts per type: "count", "attrs" (names as stored),
272
284
  # "children" (child node types), "text" (whether it holds text runs),
273
- # and "handled" ("builtin", "rule", or nil — nil marks the types you
285
+ # and "handled" ("builtin", "rule", or nil; nil marks the types you
274
286
  # still need a rule for). Children plus text is how you pick contains:.
275
287
  def node_types(root = nil)
276
288
  json = root.nil? ? @native.node_types : @native.node_types(root)
277
289
  json && JSON.parse(json)
278
290
  end
291
+
292
+ # The node types to_html can't fully render: types in the document that
293
+ # neither the built-in schema nor a registered rule handles. An unknown
294
+ # node renders its text and children without its own markup. A node that
295
+ # keeps its content only in its attributes renders nothing. Marks aren't
296
+ # listed, and an unknown mark renders its text unformatted. Returns []
297
+ # when every type is handled, and when the root is missing or isn't
298
+ # ProseMirror-shaped, because to_html returns nil there.
299
+ def unknown_types(root = nil)
300
+ types = node_types(root)
301
+ types ? types.filter_map { |type, info| type if info["handled"].nil? } : []
302
+ end
279
303
  end
280
304
 
281
305
  private_constant :NativeLexical, :NativeProseMirror
data/lib/y/tiptap.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Y
4
- # The Tiptap renderer: Y::ProseMirror (core ProseMirror — schema-basic plus
5
- # tables) plus Tiptap's extension nodes, applied beneath the app's rules —
4
+ # The Tiptap renderer: Y::ProseMirror (core ProseMirror, schema-basic plus
5
+ # tables) plus Tiptap's extension nodes, applied beneath the app's rules,
6
6
  # an app rule for one of these types simply replaces it. This is the
7
7
  # byte-parity class: the fixture tests hold `Y::Tiptap.new(doc).to_html`
8
8
  # identical to a live editor's own `getHTML()`.
9
9
  #
10
10
  # Tiptap's marks (underline, highlight, sub/superscript, textStyle) render
11
- # natively in the base class — mark serialization is text-run machinery
11
+ # natively in the base class: mark serialization is text-run machinery
12
12
  # the rule system can't express.
13
13
  class Tiptap < ProseMirror
14
14
  # Tiptap's TaskItem markup: the data-checked flag (false when unset), a
data/lib/y/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Y
4
- VERSION = "0.7.1"
4
+ VERSION = "0.8.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yrby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - JP Camara
@@ -92,19 +92,14 @@ files:
92
92
  - ext/yrby/src/lib.rs
93
93
  - ext/yrby/src/protocol.rs
94
94
  - ext/yrby/src/read.rs
95
- - ext/yrby/target/debug/build/clang-sys-e3ae45bd384f74c3/out/common.rs
96
- - ext/yrby/target/debug/build/clang-sys-e3ae45bd384f74c3/out/dynamic.rs
97
- - ext/yrby/target/debug/build/clang-sys-e3ae45bd384f74c3/out/macros.rs
98
- - ext/yrby/target/debug/build/rb-sys-4407948463231c4f/out/bindings-0.9.128-mri-arm64-darwin23-3.4.7.rs
99
- - ext/yrby/target/debug/build/rb-sys-dbeea42737529c2d/out/bindings-0.9.128-mri-arm64-darwin23-3.4.7.rs
100
- - ext/yrby/target/debug/build/serde-58ea0ee887cc2602/out/private.rs
101
- - ext/yrby/target/debug/build/serde_core-41f407c21c1f205e/out/private.rs
102
- - ext/yrby/target/debug/build/thiserror-0f1416a82ff26f22/out/private.rs
103
95
  - lib/generators/yrby/install/install_generator.rb
104
96
  - lib/generators/yrby/install/templates/document_channel.rb
105
97
  - lib/generators/yrby/tables/tables_generator.rb
106
98
  - lib/generators/yrby/tables/templates/create_y_tables.rb
107
99
  - lib/y.rb
100
+ - lib/y/collaborative.rb
101
+ - lib/y/collaborative/attribute.rb
102
+ - lib/y/collaborative/helper.rb
108
103
  - lib/y/decoder.rb
109
104
  - lib/y/lexxy.rb
110
105
  - lib/y/rendering.rb
@@ -1,355 +0,0 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
-
3
- use std::cell::RefCell;
4
- use std::collections::HashMap;
5
- use std::env;
6
- use std::path::{Path, PathBuf};
7
- use std::process::Command;
8
-
9
- use glob::{MatchOptions, Pattern};
10
-
11
- //================================================
12
- // Commands
13
- //================================================
14
-
15
- thread_local! {
16
- /// The errors encountered by the build script while executing commands.
17
- static COMMAND_ERRORS: RefCell<HashMap<String, Vec<String>>> = RefCell::default();
18
- }
19
-
20
- /// Adds an error encountered by the build script while executing a command.
21
- fn add_command_error(name: &str, path: &str, arguments: &[&str], message: String) {
22
- COMMAND_ERRORS.with(|e| {
23
- e.borrow_mut()
24
- .entry(name.into())
25
- .or_default()
26
- .push(format!(
27
- "couldn't execute `{} {}` (path={}) ({})",
28
- name,
29
- arguments.join(" "),
30
- path,
31
- message,
32
- ))
33
- });
34
- }
35
-
36
- /// A struct that prints the errors encountered by the build script while
37
- /// executing commands when dropped (unless explictly discarded).
38
- ///
39
- /// This is handy because we only want to print these errors when the build
40
- /// script fails to link to an instance of `libclang`. For example, if
41
- /// `llvm-config` couldn't be executed but an instance of `libclang` was found
42
- /// anyway we don't want to pollute the build output with irrelevant errors.
43
- #[derive(Default)]
44
- pub struct CommandErrorPrinter {
45
- discard: bool,
46
- }
47
-
48
- impl CommandErrorPrinter {
49
- pub fn discard(mut self) {
50
- self.discard = true;
51
- }
52
- }
53
-
54
- impl Drop for CommandErrorPrinter {
55
- fn drop(&mut self) {
56
- if self.discard {
57
- return;
58
- }
59
-
60
- let errors = COMMAND_ERRORS.with(|e| e.borrow().clone());
61
-
62
- if let Some(errors) = errors.get("llvm-config") {
63
- println!(
64
- "cargo:warning=could not execute `llvm-config` one or more \
65
- times, if the LLVM_CONFIG_PATH environment variable is set to \
66
- a full path to valid `llvm-config` executable it will be used \
67
- to try to find an instance of `libclang` on your system: {}",
68
- errors
69
- .iter()
70
- .map(|e| format!("\"{}\"", e))
71
- .collect::<Vec<_>>()
72
- .join("\n "),
73
- )
74
- }
75
-
76
- if let Some(errors) = errors.get("xcode-select") {
77
- println!(
78
- "cargo:warning=could not execute `xcode-select` one or more \
79
- times, if a valid instance of this executable is on your PATH \
80
- it will be used to try to find an instance of `libclang` on \
81
- your system: {}",
82
- errors
83
- .iter()
84
- .map(|e| format!("\"{}\"", e))
85
- .collect::<Vec<_>>()
86
- .join("\n "),
87
- )
88
- }
89
- }
90
- }
91
-
92
- #[cfg(test)]
93
- lazy_static::lazy_static! {
94
- pub static ref RUN_COMMAND_MOCK: std::sync::Mutex<
95
- Option<Box<dyn Fn(&str, &str, &[&str]) -> Option<String> + Send + Sync + 'static>>,
96
- > = std::sync::Mutex::new(None);
97
- }
98
-
99
- /// Executes a command and returns the `stdout` output if the command was
100
- /// successfully executed (errors are added to `COMMAND_ERRORS`).
101
- fn run_command(name: &str, path: &str, arguments: &[&str]) -> Option<String> {
102
- #[cfg(test)]
103
- if let Some(command) = &*RUN_COMMAND_MOCK.lock().unwrap() {
104
- return command(name, path, arguments);
105
- }
106
-
107
- let output = match Command::new(path).args(arguments).output() {
108
- Ok(output) => output,
109
- Err(error) => {
110
- let message = format!("error: {}", error);
111
- add_command_error(name, path, arguments, message);
112
- return None;
113
- }
114
- };
115
-
116
- if output.status.success() {
117
- Some(String::from_utf8_lossy(&output.stdout).into_owned())
118
- } else {
119
- let message = format!("exit code: {}", output.status);
120
- add_command_error(name, path, arguments, message);
121
- None
122
- }
123
- }
124
-
125
- /// Executes the `llvm-config` command and returns the `stdout` output if the
126
- /// command was successfully executed (errors are added to `COMMAND_ERRORS`).
127
- pub fn run_llvm_config(arguments: &[&str]) -> Option<String> {
128
- let path = env::var("LLVM_CONFIG_PATH").unwrap_or_else(|_| "llvm-config".into());
129
- run_command("llvm-config", &path, arguments)
130
- }
131
-
132
- /// Executes the `xcode-select` command and returns the `stdout` output if the
133
- /// command was successfully executed (errors are added to `COMMAND_ERRORS`).
134
- pub fn run_xcode_select(arguments: &[&str]) -> Option<String> {
135
- run_command("xcode-select", "xcode-select", arguments)
136
- }
137
-
138
- //================================================
139
- // Search Directories
140
- //================================================
141
- // These search directories are listed in order of
142
- // preference, so if multiple `libclang` instances
143
- // are found when searching matching directories,
144
- // the `libclang` instances from earlier
145
- // directories will be preferred (though version
146
- // takes precedence over location).
147
- //================================================
148
-
149
- /// `libclang` directory patterns for Haiku.
150
- const DIRECTORIES_HAIKU: &[&str] = &[
151
- "/boot/home/config/non-packaged/develop/lib",
152
- "/boot/home/config/non-packaged/lib",
153
- "/boot/system/non-packaged/develop/lib",
154
- "/boot/system/non-packaged/lib",
155
- "/boot/system/develop/lib",
156
- "/boot/system/lib",
157
- ];
158
-
159
- /// `libclang` directory patterns for Linux (and FreeBSD).
160
- const DIRECTORIES_LINUX: &[&str] = &[
161
- "/usr/local/llvm*/lib*",
162
- "/usr/local/lib*/*/*",
163
- "/usr/local/lib*/*",
164
- "/usr/local/lib*",
165
- "/usr/lib*/*/*",
166
- "/usr/lib*/*",
167
- "/usr/lib*",
168
- ];
169
-
170
- /// `libclang` directory patterns for macOS.
171
- const DIRECTORIES_MACOS: &[&str] = &[
172
- "/usr/local/opt/llvm*/lib/llvm*/lib",
173
- "/Library/Developer/CommandLineTools/usr/lib",
174
- "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
175
- "/usr/local/opt/llvm*/lib",
176
- ];
177
-
178
- /// `libclang` directory patterns for Windows.
179
- ///
180
- /// The boolean indicates whether the directory pattern should be used when
181
- /// compiling for an MSVC target environment.
182
- const DIRECTORIES_WINDOWS: &[(&str, bool)] = &[
183
- // LLVM + Clang can be installed using Scoop (https://scoop.sh).
184
- // Other Windows package managers install LLVM + Clang to other listed
185
- // system-wide directories.
186
- ("C:\\Users\\*\\scoop\\apps\\llvm\\current\\lib", true),
187
- ("C:\\MSYS*\\MinGW*\\lib", false),
188
- ("C:\\Program Files*\\LLVM\\lib", true),
189
- ("C:\\LLVM\\lib", true),
190
- // LLVM + Clang can be installed as a component of Visual Studio.
191
- // https://github.com/KyleMayes/clang-sys/issues/121
192
- ("C:\\Program Files*\\Microsoft Visual Studio\\*\\VC\\Tools\\Llvm\\**\\lib", true),
193
- ];
194
-
195
- /// `libclang` directory patterns for illumos
196
- const DIRECTORIES_ILLUMOS: &[&str] = &[
197
- "/opt/ooce/llvm-*/lib",
198
- "/opt/ooce/clang-*/lib",
199
- ];
200
-
201
- //================================================
202
- // Searching
203
- //================================================
204
-
205
- /// Finds the files in a directory that match one or more filename glob patterns
206
- /// and returns the paths to and filenames of those files.
207
- fn search_directory(directory: &Path, filenames: &[String]) -> Vec<(PathBuf, String)> {
208
- // Escape the specified directory in case it contains characters that have
209
- // special meaning in glob patterns (e.g., `[` or `]`).
210
- let directory = Pattern::escape(directory.to_str().unwrap());
211
- let directory = Path::new(&directory);
212
-
213
- // Join the escaped directory to the filename glob patterns to obtain
214
- // complete glob patterns for the files being searched for.
215
- let paths = filenames
216
- .iter()
217
- .map(|f| directory.join(f).to_str().unwrap().to_owned());
218
-
219
- // Prevent wildcards from matching path separators to ensure that the search
220
- // is limited to the specified directory.
221
- let mut options = MatchOptions::new();
222
- options.require_literal_separator = true;
223
-
224
- paths
225
- .map(|p| glob::glob_with(&p, options))
226
- .filter_map(Result::ok)
227
- .flatten()
228
- .filter_map(|p| {
229
- let path = p.ok()?;
230
- let filename = path.file_name()?.to_str().unwrap();
231
-
232
- // The `libclang_shared` library has been renamed to `libclang-cpp`
233
- // in Clang 10. This can cause instances of this library (e.g.,
234
- // `libclang-cpp.so.10`) to be matched by patterns looking for
235
- // instances of `libclang`.
236
- if filename.contains("-cpp.") {
237
- return None;
238
- }
239
-
240
- Some((path.parent().unwrap().to_owned(), filename.into()))
241
- })
242
- .collect::<Vec<_>>()
243
- }
244
-
245
- /// Finds the files in a directory (and any relevant sibling directories) that
246
- /// match one or more filename glob patterns and returns the paths to and
247
- /// filenames of those files.
248
- fn search_directories(directory: &Path, filenames: &[String]) -> Vec<(PathBuf, String)> {
249
- let mut results = search_directory(directory, filenames);
250
-
251
- // On Windows, `libclang.dll` is usually found in the LLVM `bin` directory
252
- // while `libclang.lib` is usually found in the LLVM `lib` directory. To
253
- // keep things consistent with other platforms, only LLVM `lib` directories
254
- // are included in the backup search directory globs so we need to search
255
- // the LLVM `bin` directory here.
256
- if target_os!("windows") && directory.ends_with("lib") {
257
- let sibling = directory.parent().unwrap().join("bin");
258
- results.extend(search_directory(&sibling, filenames));
259
- }
260
-
261
- results
262
- }
263
-
264
- /// Finds the `libclang` static or dynamic libraries matching one or more
265
- /// filename glob patterns and returns the paths to and filenames of those files.
266
- pub fn search_libclang_directories(filenames: &[String], variable: &str) -> Vec<(PathBuf, String)> {
267
- // Search only the path indicated by the relevant environment variable
268
- // (e.g., `LIBCLANG_PATH`) if it is set.
269
- if let Ok(path) = env::var(variable).map(|d| Path::new(&d).to_path_buf()) {
270
- // Check if the path is a matching file.
271
- if let Some(parent) = path.parent() {
272
- let filename = path.file_name().unwrap().to_str().unwrap();
273
- let libraries = search_directories(parent, filenames);
274
- if libraries.iter().any(|(_, f)| f == filename) {
275
- return vec![(parent.into(), filename.into())];
276
- }
277
- }
278
-
279
- // Check if the path is directory containing a matching file.
280
- return search_directories(&path, filenames);
281
- }
282
-
283
- let mut found = vec![];
284
-
285
- // Search the `bin` and `lib` directories in the directory returned by
286
- // `llvm-config --prefix`.
287
- if let Some(output) = run_llvm_config(&["--prefix"]) {
288
- let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
289
- found.extend(search_directories(&directory.join("bin"), filenames));
290
- found.extend(search_directories(&directory.join("lib"), filenames));
291
- found.extend(search_directories(&directory.join("lib64"), filenames));
292
- }
293
-
294
- // Search the toolchain directory in the directory returned by
295
- // `xcode-select --print-path`.
296
- if target_os!("macos") {
297
- if let Some(output) = run_xcode_select(&["--print-path"]) {
298
- let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
299
- let directory = directory.join("Toolchains/XcodeDefault.xctoolchain/usr/lib");
300
- found.extend(search_directories(&directory, filenames));
301
- }
302
- }
303
-
304
- // Search the directories in the `LD_LIBRARY_PATH` environment variable.
305
- if let Ok(path) = env::var("LD_LIBRARY_PATH") {
306
- for directory in env::split_paths(&path) {
307
- found.extend(search_directories(&directory, filenames));
308
- }
309
- }
310
-
311
- // Determine the `libclang` directory patterns.
312
- let directories: Vec<&str> = if target_os!("haiku") {
313
- DIRECTORIES_HAIKU.into()
314
- } else if target_os!("linux") || target_os!("freebsd") {
315
- DIRECTORIES_LINUX.into()
316
- } else if target_os!("macos") {
317
- DIRECTORIES_MACOS.into()
318
- } else if target_os!("windows") {
319
- let msvc = target_env!("msvc");
320
- DIRECTORIES_WINDOWS
321
- .iter()
322
- .filter(|d| d.1 || !msvc)
323
- .map(|d| d.0)
324
- .collect()
325
- } else if target_os!("illumos") {
326
- DIRECTORIES_ILLUMOS.into()
327
- } else {
328
- vec![]
329
- };
330
-
331
- // We use temporary directories when testing the build script so we'll
332
- // remove the prefixes that make the directories absolute.
333
- let directories = if test!() {
334
- directories
335
- .iter()
336
- .map(|d| d.strip_prefix('/').or_else(|| d.strip_prefix("C:\\")).unwrap_or(d))
337
- .collect::<Vec<_>>()
338
- } else {
339
- directories
340
- };
341
-
342
- // Search the directories provided by the `libclang` directory patterns.
343
- let mut options = MatchOptions::new();
344
- options.case_sensitive = false;
345
- options.require_literal_separator = true;
346
- for directory in directories.iter() {
347
- if let Ok(directories) = glob::glob_with(directory, options) {
348
- for directory in directories.filter_map(Result::ok).filter(|p| p.is_dir()) {
349
- found.extend(search_directories(&directory, filenames));
350
- }
351
- }
352
- }
353
-
354
- found
355
- }