Skip to content

Commit a086887

Browse files
authored
Change completions of regex literals (#7425)
* change completions of regex literals * more sustainable fix, that also covers completions for all stdlib modules * update test output * refactor * changelog
1 parent 3cbc730 commit a086887

File tree

10 files changed

+97
-12
lines changed

10 files changed

+97
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#### :nail_care: Polish
2424

2525
- Suggest awaiting promise before using it when types mismatch. https://github.com/rescript-lang/rescript/pull/7498
26+
- Complete from `RegExp` stdlib module for regexes. https://github.com/rescript-lang/rescript/pull/7425
2627

2728
# 12.0.0-alpha.13
2829

analysis/src/TypeUtils.ml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1265,4 +1265,9 @@ let completionPathFromMaybeBuiltin path =
12651265
| Some ("result", _) -> Some ["Stdlib"; "Result"]
12661266
| Some ("dict", _) -> Some ["Stdlib"; "Dict"]
12671267
| Some ("char", _) -> Some ["Stdlib"; "Char"]
1268-
| _ -> None
1268+
| _ -> (
1269+
match path |> Utils.expandPath |> List.rev with
1270+
| [mainModule; "t"] when String.starts_with ~prefix:"Stdlib_" mainModule ->
1271+
(* Route Stdlib_X to Stdlib.X for proper completions without the Stdlib_ prefix *)
1272+
Some (String.split_on_char '_' mainModule)
1273+
| _ -> None)

compiler/frontend/ast_comb.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ let tuple_type_pair ?loc kind arity =
5757
result )
5858
| [] -> assert false
5959

60-
let re_id = Ast_literal.Lid.js_re_id
60+
let regexp_id = Ast_literal.Lid.regexp_id
6161

62-
let to_js_re_type loc = Typ.constr ~loc {txt = re_id; loc} []
62+
let to_regexp_type loc = Typ.constr ~loc {txt = regexp_id; loc} []
6363

6464
let to_undefined_type loc x =
6565
Typ.constr ~loc {txt = Ast_literal.Lid.js_undefined; loc} [x]

compiler/frontend/ast_comb.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ val tuple_type_pair :
3939

4040
val to_undefined_type : Location.t -> Parsetree.core_type -> Parsetree.core_type
4141

42-
val to_js_re_type : Location.t -> Parsetree.core_type
42+
val to_regexp_type : Location.t -> Parsetree.core_type
4343

4444
val single_non_rec_value :
4545
?attrs:Parsetree.attributes ->

compiler/frontend/ast_exp_extension.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ let handle_extension e (self : Bs_ast_mapper.mapper)
6060
| "re" ->
6161
Exp.constraint_ ~loc
6262
(Ast_exp_handle_external.handle_raw ~kind:Raw_re loc payload)
63-
(Ast_comb.to_js_re_type loc)
63+
(Ast_comb.to_regexp_type loc)
6464
| "external" -> (
6565
Location.deprecated loc
6666
"%external is deprecated, use %raw or regular FFI syntax instead.";

compiler/frontend/ast_literal.ml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ module Lid = struct
7070
(* FIXME: Use primitive module *)
7171
let js_null_undefined : t = Ldot (Lident "Js", "null_undefined")
7272

73-
(* FIXME: Use primitive module *)
74-
let js_re_id : t = Ldot (Ldot (Lident "Js", "Re"), "t")
73+
let regexp_id : t = Ldot (Lident "Stdlib_RegExp", "t")
7574
end
7675

7776
module No_loc = struct

compiler/frontend/ast_literal.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ module Lid : sig
5757

5858
val js_null_undefined : t
5959

60-
val js_re_id : t
60+
val regexp_id : t
6161
end
6262

6363
type expression_lit = Parsetree.expression lit
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
let emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
2+
// emailPattern->
3+
// ^com

tests/analysis_tests/tests/src/expected/CompletionPipeChain.res.txt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -582,15 +582,14 @@ Resolved opens 1 Stdlib
582582
ContextPath Value[r]->la
583583
ContextPath Value[r]
584584
Path r
585-
CPPipe pathFromEnv:Js.Re found:false
586-
Path Js.Re.la
585+
Path Stdlib.RegExp.la
587586
Path la
588587
[{
589-
"label": "Js.Re.lastIndex",
588+
"label": "RegExp.lastIndex",
590589
"kind": 12,
591590
"tags": [],
592591
"detail": "t => int",
593-
"documentation": {"kind": "markdown", "value": "\nReturns the index where the next match will start its search. This property\nwill be modified when the RegExp object is used, if the global (\"g\") flag is\nset.\n\n## Examples\n\n```rescript\nlet re = /ab*TODO/g\nlet str = \"abbcdefabh\"\n\nlet break = ref(false)\nwhile !break.contents {\n switch Js.Re.exec_(re, str) {\n | Some(result) => Js.Nullable.iter(Js.Re.captures(result)[0], (. match_) => {\n let next = Belt.Int.toString(Js.Re.lastIndex(re))\n Js.log(\"Found \" ++ (match_ ++ (\". Next match starts at \" ++ next)))\n })\n | None => break := true\n }\n}\n```\n\nSee\n[`RegExp: lastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex)\non MDN.\n"}
592+
"documentation": {"kind": "markdown", "value": "\n`lastIndex(regexp)` returns the index the next match will start from.\n\nSee [`RegExp.lastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex) on MDN.\n\n## Examples\n```rescript\n// Match the first word in a sentence\nlet regexp = RegExp.fromString(\"\\\\w+\")\nlet someStr = \"Many words here.\"\n\nConsole.log(regexp->RegExp.lastIndex) // Logs `0` to the console\n\nregexp->RegExp.exec(someStr)->ignore\n\nConsole.log(regexp->RegExp.lastIndex) // Logs `4` to the console\n```\n"}
594593
}]
595594

596595
Complete src/CompletionPipeChain.res 112:7
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
Complete src/CompletionRegexp.res 1:17
2+
posCursor:[1:17] posNoWhite:[1:16] Found expr:[1:3->0:-1]
3+
Completable: Cpath Value[emailPattern]->
4+
Package opens Stdlib.place holder Pervasives.JsxModules.place holder
5+
Resolved opens 1 Stdlib
6+
ContextPath Value[emailPattern]->
7+
ContextPath Value[emailPattern]
8+
Path emailPattern
9+
Path Stdlib.RegExp.
10+
Path
11+
[{
12+
"label": "RegExp.lastIndex",
13+
"kind": 12,
14+
"tags": [],
15+
"detail": "t => int",
16+
"documentation": {"kind": "markdown", "value": "\n`lastIndex(regexp)` returns the index the next match will start from.\n\nSee [`RegExp.lastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex) on MDN.\n\n## Examples\n```rescript\n// Match the first word in a sentence\nlet regexp = RegExp.fromString(\"\\\\w+\")\nlet someStr = \"Many words here.\"\n\nConsole.log(regexp->RegExp.lastIndex) // Logs `0` to the console\n\nregexp->RegExp.exec(someStr)->ignore\n\nConsole.log(regexp->RegExp.lastIndex) // Logs `4` to the console\n```\n"}
17+
}, {
18+
"label": "RegExp.setLastIndex",
19+
"kind": 12,
20+
"tags": [],
21+
"detail": "(t, int) => unit",
22+
"documentation": {"kind": "markdown", "value": "\n`setLastIndex(regexp, index)` set the index the next match will start from.\n\nSee [`RegExp.lastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex) on MDN.\n\n## Examples\n```rescript\n// Match the first word in a sentence\nlet regexp = RegExp.fromString(\"\\\\w+\")\nlet someStr = \"Many words here.\"\n\nregexp->RegExp.setLastIndex(4)\nregexp->RegExp.exec(someStr)->ignore\n\nConsole.log(regexp->RegExp.lastIndex) // Logs `10` to the console\n```\n"}
23+
}, {
24+
"label": "RegExp.sticky",
25+
"kind": 12,
26+
"tags": [],
27+
"detail": "t => bool",
28+
"documentation": {"kind": "markdown", "value": "\n`sticky(regexp)` returns whether the sticky (`y`) flag is set on this `RegExp`.\n\nSee [`RegExp.sticky`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky) on MDN.\n\n## Examples\n```rescript\nlet regexp1 = RegExp.fromStringWithFlags(\"\\\\w+\", ~flags=\"g\")\nConsole.log(regexp1->RegExp.unicode) // Logs `false`, since `y` is not set\n\nlet regexp2 = RegExp.fromStringWithFlags(\"\\\\w+\", ~flags=\"my\")\nConsole.log(regexp2->RegExp.unicode) // Logs `true`, since `y` is set\n```\n"}
29+
}, {
30+
"label": "RegExp.ignore",
31+
"kind": 12,
32+
"tags": [],
33+
"detail": "t => unit",
34+
"documentation": {"kind": "markdown", "value": "\n `ignore(regExp)` ignores the provided regExp and returns unit.\n\n This helper is useful when you want to discard a value (for example, the result of an operation with side effects)\n without having to store or process it further.\n"}
35+
}, {
36+
"label": "RegExp.exec",
37+
"kind": 12,
38+
"tags": [],
39+
"detail": "(t, string) => option<Result.t>",
40+
"documentation": {"kind": "markdown", "value": "\n`exec(regexp, string)` executes the provided regexp on the provided string, optionally returning a `RegExp.Result.t` if the regexp matches on the string.\n\nSee [`RegExp.exec`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec) on MDN.\n\n## Examples\n```rescript\n// Match the first word in a sentence\nlet regexp = RegExp.fromString(\"\\\\w+\")\n\nswitch regexp->RegExp.exec(\"ReScript is pretty cool, right?\") {\n| None => Console.log(\"Nope, no match...\")\n| Some(result) => Console.log(result->RegExp.Result.fullMatch) // Prints \"ReScript\"\n}\n```\n"}
41+
}, {
42+
"label": "RegExp.ignoreCase",
43+
"kind": 12,
44+
"tags": [],
45+
"detail": "t => bool",
46+
"documentation": {"kind": "markdown", "value": "\n`ignoreCase(regexp)` returns whether the ignore case (`i`) flag is set on this `RegExp`.\n\nSee [`RegExp.ignoreCase`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/ignoreCase) on MDN.\n\n## Examples\n```rescript\nlet regexp1 = RegExp.fromStringWithFlags(\"\\\\w+\", ~flags=\"g\")\nConsole.log(regexp1->RegExp.ignoreCase) // Logs `false`, since `i` is not set\n\nlet regexp2 = RegExp.fromStringWithFlags(\"\\\\w+\", ~flags=\"i\")\nConsole.log(regexp2->RegExp.ignoreCase) // Logs `true`, since `i` is set\n```\n"}
47+
}, {
48+
"label": "RegExp.global",
49+
"kind": 12,
50+
"tags": [],
51+
"detail": "t => bool",
52+
"documentation": {"kind": "markdown", "value": "\n`global(regexp)` returns whether the global (`g`) flag is set on this `RegExp`.\n\nSee [`RegExp.global`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/global) on MDN.\n\n## Examples\n```rescript\nlet regexp1 = RegExp.fromStringWithFlags(\"\\\\w+\", ~flags=\"g\")\nConsole.log(regexp1->RegExp.global) // Logs `true`, since `g` is set\n\nlet regexp2 = RegExp.fromStringWithFlags(\"\\\\w+\", ~flags=\"i\")\nConsole.log(regexp2->RegExp.global) // Logs `false`, since `g` is not set\n```\n"}
53+
}, {
54+
"label": "RegExp.multiline",
55+
"kind": 12,
56+
"tags": [],
57+
"detail": "t => bool",
58+
"documentation": {"kind": "markdown", "value": "\n`multiline(regexp)` returns whether the multiline (`m`) flag is set on this `RegExp`.\n\nSee [`RegExp.multiline`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/multiline) on MDN.\n\n## Examples\n```rescript\nlet regexp1 = RegExp.fromStringWithFlags(\"\\\\w+\", ~flags=\"g\")\nConsole.log(regexp1->RegExp.multiline) // Logs `false`, since `m` is not set\n\nlet regexp2 = RegExp.fromStringWithFlags(\"\\\\w+\", ~flags=\"mi\")\nConsole.log(regexp2->RegExp.multiline) // Logs `true`, since `m` is set\n```\n"}
59+
}, {
60+
"label": "RegExp.test",
61+
"kind": 12,
62+
"tags": [],
63+
"detail": "(t, string) => bool",
64+
"documentation": {"kind": "markdown", "value": "\n`test(regexp, string)` tests whether the provided `regexp` matches on the provided string.\n\nSee [`RegExp.test`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test) on MDN.\n\n## Examples\n```rescript\n// Match the first word in a sentence\nlet regexp = RegExp.fromString(\"\\\\w+\")\n\nif regexp->RegExp.test(\"ReScript is cool!\") {\n Console.log(\"Yay, there's a word in there.\")\n}\n```\n"}
65+
}, {
66+
"label": "RegExp.unicode",
67+
"kind": 12,
68+
"tags": [],
69+
"detail": "t => bool",
70+
"documentation": {"kind": "markdown", "value": "\n`unicode(regexp)` returns whether the unicode (`y`) flag is set on this `RegExp`.\n\nSee [`RegExp.unicode`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode) on MDN.\n\n## Examples\n```rescript\nlet regexp1 = RegExp.fromStringWithFlags(\"\\\\w+\", ~flags=\"g\")\nConsole.log(regexp1->RegExp.unicode) // Logs `false`, since `u` is not set\n\nlet regexp2 = RegExp.fromStringWithFlags(\"\\\\w+\", ~flags=\"mu\")\nConsole.log(regexp2->RegExp.unicode) // Logs `true`, since `u` is set\n```\n"}
71+
}, {
72+
"label": "RegExp.source",
73+
"kind": 12,
74+
"tags": [],
75+
"detail": "t => string",
76+
"documentation": {"kind": "markdown", "value": "\n`source(regexp)` returns the source text for this `RegExp`, without the two forward slashes (if present), and without any set flags.\n\nSee [`RegExp.source`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/source) on MDN.\n\n## Examples\n```rescript\nlet regexp = RegExp.fromStringWithFlags(\"\\\\w+\", ~flags=\"g\")\nConsole.log(regexp->RegExp.source) // Logs `\\w+`, the source text of the `RegExp`\n```\n"}
77+
}]
78+

0 commit comments

Comments
 (0)