diff --git a/src/lib/uTop_complete.cppo.ml b/src/lib/uTop_complete.cppo.ml index 6c13d8a..bdeaeaa 100644 --- a/src/lib/uTop_complete.cppo.ml +++ b/src/lib/uTop_complete.cppo.ml @@ -74,7 +74,7 @@ let parse_longident tokens = | l -> Some (longident_of_list l)) in match tokens with - | ((Comment (_, false) | String false | Quotation (_, false)), _) :: _ -> + | ((Comment (_, false) | String (_, false) | Quotation (_, false)), _) :: _ -> (* An unterminated command, string, or quotation. *) None | ((Uident id | Lident id), { idx1 = start }) :: tokens -> @@ -847,23 +847,23 @@ let complete ~syntax ~phrase_terminator ~input = (start, lookup_assoc src (list_directives phrase_terminator)) (* Complete with ";;" when possible. *) - | [(Symbol "#", _); ((Lident _ | Uident _), _); (String true, { idx2 = stop })] - | [(Symbol "#", _); ((Lident _ | Uident _), _); (String true, _); (Blanks, { idx2 = stop })] -> + | [(Symbol "#", _); ((Lident _ | Uident _), _); (String (_, true), { idx2 = stop })] + | [(Symbol "#", _); ((Lident _ | Uident _), _); (String (_, true), _); (Blanks, { idx2 = stop })] -> (stop, [(phrase_terminator, "")]) - | [(Symbol "#", _); ((Lident _ | Uident _), _); (String true, _); (Symbol sym, { idx1 = start })] -> + | [(Symbol "#", _); ((Lident _ | Uident _), _); (String (_, true), _); (Symbol sym, { idx1 = start })] -> if Zed_utf8.starts_with phrase_terminator sym then (start, [(phrase_terminator, "")]) else (0, []) (* Completion on #require. *) - | [(Symbol "#", _); (Lident "require", _); (String false, loc)] -> - let pkg = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in + | [(Symbol "#", _); (Lident "require", _); (String (tlen, false), loc)] -> + let pkg = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in let pkgs = lookup pkg (Fl_package_base.list_packages ()) in (loc.idx1 + 1, List.map (fun pkg -> (pkg, "\"" ^ phrase_terminator)) (List.sort compare pkgs)) - | [(Symbol "#", _); (Lident "typeof", _); (String false, loc)] -> - let prefix = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in + | [(Symbol "#", _); (Lident "typeof", _); (String (tlen, false), loc)] -> + let prefix = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in begin match Longident.parse prefix with | Longident.Ldot (lident, last_prefix) -> let set = names_of_module lident in @@ -877,8 +877,8 @@ let complete ~syntax ~phrase_terminator ~input = end (* Completion on #load. *) - | [(Symbol "#", _); (Lident ("load" | "load_rec"), _); (String false, loc)] -> - let file = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in + | [(Symbol "#", _); (Lident ("load" | "load_rec"), _); (String (tlen, false), loc)] -> + let file = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in let filter name = Filename.check_suffix name ".cma" || Filename.check_suffix name ".cmo" in let map = if Filename.is_relative file then @@ -898,8 +898,8 @@ let complete ~syntax ~phrase_terminator ~input = #if OCAML_VERSION >= (4, 02, 0) (* Completion on #ppx. *) - | [(Symbol "#", _); (Lident ("ppx"), _); (String false, loc)] -> - let file = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in + | [(Symbol "#", _); (Lident ("ppx"), _); (String (tlen, false), loc)] -> + let file = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in let filter ~dir_ok name = try Unix.access name [Unix.X_OK]; @@ -928,8 +928,8 @@ let complete ~syntax ~phrase_terminator ~input = #endif (* Completion on #use. *) - | [(Symbol "#", _); (Lident "use", _); (String false, loc)] -> - let file = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in + | [(Symbol "#", _); (Lident "use", _); (String (tlen, false), loc)] -> + let file = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in let filter name = match try Some (String.rindex name '.') with Not_found -> None with | None -> @@ -955,8 +955,8 @@ let complete ~syntax ~phrase_terminator ~input = List.map (function (w, Directory) -> (w, "") | (w, File) -> (w, "\"" ^ phrase_terminator)) result) (* Completion on #directory and #cd. *) - | [(Symbol "#", _); (Lident ("cd" | "directory"), _); (String false, loc)] -> - let file = String.sub input (loc.ofs1 + 1) (String.length input - loc.ofs1 - 1) in + | [(Symbol "#", _); (Lident ("cd" | "directory"), _); (String (tlen, false), loc)] -> + let file = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in let list = list_directories (Filename.dirname file) in let name = basename file in let result = lookup name list in diff --git a/src/lib/uTop_lexer.mll b/src/lib/uTop_lexer.mll index 9edb25f..6706201 100644 --- a/src/lib/uTop_lexer.mll +++ b/src/lib/uTop_lexer.mll @@ -117,7 +117,13 @@ rule tokens syntax context idx acc = parse { let ofs = lexeme_start lexbuf in let idx2, terminated = string (idx + 1) lexbuf in let loc = mkloc idx idx2 ofs (lexeme_end lexbuf) in - tokens syntax context idx2 ((String terminated, loc) :: acc) lexbuf } + tokens syntax context idx2 ((String (1, terminated), loc) :: acc) lexbuf } + | '{' (lowercase* as tag) '|' + { let ofs = lexeme_start lexbuf in + let delim_len = String.length tag + 2 in + let idx2, terminated = quoted_string (idx + delim_len) tag lexbuf in + let loc = mkloc idx idx2 ofs (lexeme_end lexbuf) in + tokens syntax context idx2 ((String (delim_len, terminated), loc) :: acc) lexbuf } | "'" [^'\'' '\\'] "'" | "'\\" ['\\' '"' 'n' 't' 'b' 'r' ' ' '\'' 'x' '0'-'9'] eof | "'\\" ['\\' '"' 'n' 't' 'b' 'r' ' ' '\''] "'" @@ -217,6 +223,18 @@ and string idx = parse | eof { (idx, false) } +and quoted_string idx tag = parse + | '|' (lowercase* as tag2) '}' + { let idx = idx + 2 + String.length tag2 in + if tag = tag2 then + (idx, true) + else + quoted_string idx tag lexbuf } + | eof + { (idx, false) } + | uchar + { quoted_string (idx + 1) tag lexbuf } + and quotation syntax depth idx1 idx2 ofs1 = parse | '<' (':' ident)? ('@' lident)? '<' { quotation syntax (depth + 1) idx1 (idx2 + lexeme_size lexbuf) ofs1 lexbuf } diff --git a/src/lib/uTop_token.ml b/src/lib/uTop_token.ml index b077c26..57d948c 100644 --- a/src/lib/uTop_token.ml +++ b/src/lib/uTop_token.ml @@ -30,8 +30,8 @@ type t = | Uident of string | Constant of string | Char - | String of bool - (** [String terminated]. *) + | String of int * bool + (** [String (quote_size, terminated)]. *) | Comment of comment_kind * bool (** [Comment (kind, terminated)]. *) | Blanks