hackwaly / vscode-ocaml

An extension for VS Code which provides support for the OCaml language.
MIT License
170 stars 26 forks source link

Merlin support breaks when it returns unicode #100

Closed ryanslade closed 7 years ago

ryanslade commented 7 years ago

When using containers and attempting to get code completion of the List module completion breaks and I need to restart merlin.

The JSON parser here (https://github.com/hackwaly/vscode-ocaml/blob/a1cfb2b9381b4de7041daf0b5737291edb9814a4/src/merlin.ts#L64) appears to break due to unicode characters returned in the merlin answer. They appear to come from here: https://github.com/c-cube/ocaml-containers/blob/d659ba677e3dbd95430f59b3794ac2f2a5677d61/src/core/CCList.mli#L127

See the '…' character

hackwaly commented 7 years ago

Could you please paste the merlin answer which cause bug here?

ryanslade commented 7 years ago
["return",{"entries":[{"name":"<$>","kind":"Value","desc":"('a -> 'b) -> 'a Containers.List.t -> 'b Containers.List.t","info":""},{"name":"<*>","kind":"Value","desc":"('a -> 'b) Containers.List.t -> 'a Containers.List.t -> 'b Containers.List.t","info":""},{"name":">>=","kind":"Value","desc":"'a Containers.List.t -> ('a -> 'b Containers.List.t) -> 'b Containers.List.t","info":""},{"name":">|=","kind":"Value","desc":"'a Containers.List.t -> ('a -> 'b) -> 'b Containers.List.t","info":" Infix version of [map] with reversed arguments\n    @since 0.5 "},{"name":"@","kind":"Value","desc":"'a Containers.List.t -> 'a Containers.List.t -> 'a Containers.List.t","info":""},{"name":"add_nodup","kind":"Value","desc":"?eq:('a -> 'a -> bool) -> 'a -> 'a Containers.List.t -> 'a Containers.List.t","info":" [add_nodup x set] adds [x] to [set] if it was not already present. Linear time.\n    @since 0.11 "},{"name":"append","kind":"Value","desc":"'a Containers.List.t -> 'a Containers.List.t -> 'a Containers.List.t","info":" Safe version of append "},{"name":"assoc","kind":"Value","desc":"'a -> ('a * 'b) list -> 'b","info":" [assoc a l] returns the value associated with key [a] in the list of\n   pairs [l]. That is,\n   [assoc a [ ...; (a,b); ...] = b]\n   if [(a,b)] is the leftmost binding of [a] in list [l].\n   Raise [Not_found] if there is no value associated with [a] in the\n   list [l]. "},{"name":"assq","kind":"Value","desc":"'a -> ('a * 'b) list -> 'b","info":" Same as {!List.assoc}, but uses physical equality instead of structural\n   equality to compare keys. "},{"name":"cartesian_product","kind":"Value","desc":"'a Containers.List.t Containers.List.t ->\n'a Containers.List.t Containers.List.t","info":"\n    For example:\n    {[\n      # cartesian_product [[1;2];[3];[4;5;6]] =\n          [[1;3;4];[1;3;5];[1;3;6];[2;3;4];[2;3;5];[2;3;6]];;\n      # cartesian_product [[1;2];[];[4;5;6]] = [];;\n      # cartesian_product [[1;2];[3];[4];[5];[6]] =\n          [[1;3;4;5;6];[2;3;4;5;6]];;\n    ]}\n    invariant: [cartesian_product l = map_product id l].\n    @since 1.2 "},{"name":"combine","kind":"Value","desc":"'a list -> 'b list -> ('a * 'b) list","info":" Similar to {!List.combine} but tail-recursive.\n    @raise Invalid_argument if the lists have distinct lengths.\n    @since 1.2 "},{"name":"combine_gen","kind":"Value","desc":"'a list -> 'b list -> ('a * 'b) Containers.List.gen","info":" Lazy version of {!combine}.\n    Unlike {!combine}, it does not fail if the lists have different\n    lengths;\n    instead, the output has as many pairs as the smallest input list.\n    @since 1.2 "},{"name":"compare","kind":"Value","desc":"('a -> 'a -> int) -> 'a Containers.List.t -> 'a Containers.List.t -> int","info":""},{"name":"concat","kind":"Value","desc":"'a list list -> 'a list","info":" Concatenate a list of lists.  The elements of the argument are all\n   concatenated together (in the same order) to give the result.\n   Not tail-recursive\n   (length of the argument + length of the longest sub-list). "},{"name":"cons","kind":"Value","desc":"'a -> 'a Containers.List.t -> 'a Containers.List.t","info":" [cons x l] is [x::l]\n    @since 0.12 "},{"name":"cons_maybe","kind":"Value","desc":"'a option -> 'a Containers.List.t -> 'a Containers.List.t","info":" [cons_maybe (Some x) l] is [x :: l]\n    [cons_maybe None l] is [l]\n    @since 0.13 "},{"name":"diagonal","kind":"Value","desc":"'a Containers.List.t -> ('a * 'a) Containers.List.t","info":" All pairs of distinct positions of the list. [list_diagonal l] will\n    return the list of [List.nth i l, List.nth j l] if [i < j]. "},{"name":"drop","kind":"Value","desc":"int -> 'a Containers.List.t -> 'a Containers.List.t","info":" Drop the [n] first elements, keep the rest "},{"name":"drop_while","kind":"Value","desc":"('a -> bool) -> 'a Containers.List.t -> 'a Containers.List.t","info":" @since 0.13 "},{"name":"empty","kind":"Value","desc":"'a Containers.List.t","info":""},{"name":"equal","kind":"Value","desc":"('a -> 'a -> bool) -> 'a Containers.List.t -> 'a Containers.List.t -> bool","info":""},{"name":"exists","kind":"Value","desc":"('a -> bool) -> 'a list -> bool","info":" [exists p [a1; ...; an]] checks if at least one element of\n   the list satisfies the predicate [p]. That is, it returns\n   [(p a1) || (p a2) || ... || (p an)]. "},{"name":"exists2","kind":"Value","desc":"('a -> 'b -> bool) -> 'a list -> 'b list -> bool","info":" Same as {!List.exists}, but for a two-argument predicate.\n   Raise [Invalid_argument] if the two lists are determined\n   to have different lengths. "},{"name":"fast_sort","kind":"Value","desc":"('a -> 'a -> int) -> 'a list -> 'a list","info":" Same as {!List.sort} or {!List.stable_sort}, whichever is faster\n    on typical input. "},{"name":"filter","kind":"Value","desc":"('a -> bool) -> 'a Containers.List.t -> 'a Containers.List.t","info":" Safe version of {!List.filter} "},{"name":"filter_map","kind":"Value","desc":"('a -> 'b option) -> 'a Containers.List.t -> 'b Containers.List.t","info":" Map and remove elements at the same time "},{"name":"find","kind":"Value","desc":"('a -> bool) -> 'a list -> 'a","info":" [find p l] returns the first element of the list [l]\n   that satisfies the predicate [p].\n   Raise [Not_found] if there is no value that satisfies [p] in the\n   list [l]. "},{"name":"find_all","kind":"Value","desc":"('a -> bool) -> 'a list -> 'a list","info":" [find_all] is another name for {!List.filter}. "},{"name":"find_idx","kind":"Value","desc":"('a -> bool) -> 'a Containers.List.t -> (int * 'a) option","info":" [find_idx p x] returns [Some (i,x)] where [x] is the [i]-th element of [l],\n    and [p x] holds. Otherwise returns [None] "},{"name":"find_map","kind":"Value","desc":"('a -> 'b option) -> 'a Containers.List.t -> 'b option","info":" [find_map f l] traverses [l], applying [f] to each element. If for\n    some element [x], [f x = Some y], then [Some y] is returned. Otherwise\n    the call returns [None]\n    @since 0.11 "},{"name":"find_mapi","kind":"Value","desc":"(int -> 'a -> 'b option) -> 'a Containers.List.t -> 'b option","info":" Like {!find_map}, but also pass the index to the predicate function.\n    @since 0.11 "},{"name":"find_pred","kind":"Value","desc":"('a -> bool) -> 'a Containers.List.t -> 'a option","info":" [find_pred p l] finds the first element of [l] that satisfies [p],\n    or returns [None] if no element satisfies [p]\n    @since 0.11 "},{"name":"find_pred_exn","kind":"Value","desc":"('a -> bool) -> 'a Containers.List.t -> 'a","info":" Unsafe version of {!find_pred}\n    @raise Not_found if no such element is found\n    @since 0.11 "},{"name":"flat_map","kind":"Value","desc":"('a -> 'b Containers.List.t) -> 'a Containers.List.t -> 'b Containers.List.t","info":" Map and flatten at the same time (safe). Evaluation order is not guaranteed. "},{"name":"flatten","kind":"Value","desc":"'a Containers.List.t Containers.List.t -> 'a Containers.List.t","info":" Safe flatten "},{"name":"fold_filter_map","kind":"Value","desc":"('acc -> 'a -> 'acc * 'b option) -> 'acc -> 'a list -> 'acc * 'b list","info":" [fold_filter_map f acc l] is a [fold_left]-like function, but also\n    generates a list of output in a way similar to {!filter_map}\n    @since 0.17 "},{"name":"fold_flat_map","kind":"Value","desc":"('acc -> 'a -> 'acc * 'b list) -> 'acc -> 'a list -> 'acc * 'b list","info":" [fold_flat_map f acc l] is a [fold_left]-like function, but it also maps the\n    list to a list of lists that is then [flatten]'d..\n    @since 0.14 "},{"name":"fold_left","kind":"Value","desc":"('a -> 'b -> 'a) -> 'a -> 'b list -> 'a","info":" [List.fold_left f a [b1; ...; bn]] is\n   [f (... (f (f a b1) b2) ...) bn]. "},{"name":"fold_left2","kind":"Value","desc":"('a -> 'b -> 'c -> 'a) -> 'a -> 'b list -> 'c list -> 'a","info":" [List.fold_left2 f a [b1; ...; bn] [c1; ...; cn]] is\n   [f (... (f (f a b1 c1) b2 c2) ...) bn cn].\n   Raise [Invalid_argument] if the two lists are determined\n   to have different lengths. "},{"name":"fold_map","kind":"Value","desc":"('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a list -> 'acc * 'b list","info":" [fold_map f acc l] is a [fold_left]-like function, but it also maps the\n    list to another list.\n    @since 0.14 "},{"name":"fold_map2","kind":"Value","desc":"('acc -> 'a -> 'b -> 'acc * 'c) ->\n'acc -> 'a list -> 'b list -> 'acc * 'c list","info":" [fold_map2] is to [fold_map] what [List.map2] is to [List.map].\n    @raise Invalid_argument if the lists do not have the same length\n    @since 0.16 "},{"name":"fold_product","kind":"Value","desc":"('c -> 'a -> 'b -> 'c) ->\n'c -> 'a Containers.List.t -> 'b Containers.List.t -> 'c","info":" Fold on the cartesian product "},{"name":"fold_right","kind":"Value","desc":"('a -> 'b -> 'b) -> 'a Containers.List.t -> 'b -> 'b","info":" Safe version of [fold_right] "},{"name":"fold_right2","kind":"Value","desc":"('a -> 'b -> 'c -> 'c) -> 'a list -> 'b list -> 'c -> 'c","info":" [List.fold_right2 f [a1; ...; an] [b1; ...; bn] c] is\n   [f a1 b1 (f a2 b2 (... (f an bn c) ...))].\n   Raise [Invalid_argument] if the two lists are determined\n   to have different lengths.  Not tail-recursive. "},{"name":"fold_while","kind":"Value","desc":"('a -> 'b -> 'a * [ `Continue | `Stop ]) -> 'a -> 'b Containers.List.t -> 'a","info":" Fold until a stop condition via [('a, `Stop)] is\n    indicated by the accumulator\n    @since 0.8 "},{"name":"foldi","kind":"Value","desc":"('b -> int -> 'a -> 'b) -> 'b -> 'a Containers.List.t -> 'b","info":" Fold on list, with index "},{"name":"for_all","kind":"Value","desc":"('a -> bool) -> 'a list -> bool","info":" [for_all p [a1; ...; an]] checks if all elements of the list\n   satisfy the predicate [p]. That is, it returns\n   [(p a1) && (p a2) && ... && (p an)]. "},{"name":"for_all2","kind":"Value","desc":"('a -> 'b -> bool) -> 'a list -> 'b list -> bool","info":" Same as {!List.for_all}, but for a two-argument predicate.\n   Raise [Invalid_argument] if the two lists are determined\n   to have different lengths. "},{"name":"get_at_idx","kind":"Value","desc":"int -> 'a Containers.List.t -> 'a option","info":""},{"name":"get_at_idx_exn","kind":"Value","desc":"int -> 'a Containers.List.t -> 'a","info":" Get the i-th element, or\n    @raise Not_found if the index is invalid "},{"name":"group_succ","kind":"Value","desc":"?eq:('a -> 'a -> bool) -> 'a list -> 'a list list","info":" [group_succ ~eq l] groups together consecutive elements that are equal\n    according to [eq]\n    @since 0.11 "},{"name":"hd","kind":"Value","desc":"'a list -> 'a","info":" Return the first element of the given list. Raise\n   [Failure \"hd\"] if the list is empty. "},{"name":"hd_tl","kind":"Value","desc":"'a Containers.List.t -> 'a * 'a Containers.List.t","info":" [hd_tl (x :: l)] returns [hd, l].\n    @raise Failure if the list is empty\n    @since 0.16 "},{"name":"head_opt","kind":"Value","desc":"'a Containers.List.t -> 'a option","info":" First element.\n    @since 0.20 "},{"name":"init","kind":"Value","desc":"int -> (int -> 'a) -> 'a Containers.List.t","info":" Similar to {!Array.init}\n    @since 0.6 "},{"name":"insert_at_idx","kind":"Value","desc":"int -> 'a -> 'a Containers.List.t -> 'a Containers.List.t","info":" Insert at i-th position, between the two existing elements. If the\n    index is too high, append at the end of the list "},{"name":"inter","kind":"Value","desc":"?eq:('a -> 'a -> bool) ->\n'a Containers.List.t -> 'a Containers.List.t -> 'a Containers.List.t","info":" List intersection. Complexity is product of length of inputs. "},{"name":"is_empty","kind":"Value","desc":"'a Containers.List.t -> bool","info":" [is_empty l] returns [true] iff [l = []]\n    @since 0.11 "},{"name":"is_sorted","kind":"Value","desc":"?cmp:('a -> 'a -> int) -> 'a list -> bool","info":" [is_sorted l] returns [true] iff [l] is sorted (according to given order)\n    @param cmp the comparison function (default [Pervasives.compare])\n    @since 0.17 "},{"name":"iter","kind":"Value","desc":"('a -> unit) -> 'a list -> unit","info":" [List.iter f [a1; ...; an]] applies function [f] in turn to\n   [a1; ...; an]. It is equivalent to\n   [begin f a1; f a2; ...; f an; () end]. "},{"name":"iter2","kind":"Value","desc":"('a -> 'b -> unit) -> 'a list -> 'b list -> unit","info":" [List.iter2 f [a1; ...; an] [b1; ...; bn]] calls in turn\n   [f a1 b1; ...; f an bn].\n   Raise [Invalid_argument] if the two lists are determined\n   to have different lengths. "},{"name":"iteri","kind":"Value","desc":"(int -> 'a -> unit) -> 'a Containers.List.t -> unit","info":""},{"name":"last","kind":"Value","desc":"int -> 'a Containers.List.t -> 'a Containers.List.t","info":" [last n l] takes the last [n] elements of [l] (or less if\n    [l] doesn't have that many elements "},{"name":"last_opt","kind":"Value","desc":"'a Containers.List.t -> 'a option","info":" Last element.\n    @since 0.20 "},{"name":"length","kind":"Value","desc":"'a list -> int","info":" Return the length (number of elements) of the given list. "},{"name":"map","kind":"Value","desc":"('a -> 'b) -> 'a Containers.List.t -> 'b Containers.List.t","info":" Safe version of map "},{"name":"map2","kind":"Value","desc":"('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list","info":" [List.map2 f [a1; ...; an] [b1; ...; bn]] is\n   [[f a1 b1; ...; f an bn]].\n   Raise [Invalid_argument] if the two lists are determined\n   to have different lengths.  Not tail-recursive. "},{"name":"map_product_l","kind":"Value","desc":"('a -> 'b list) -> 'a list -> 'b list list","info":" [map_product_l f l] maps each element of [l] to a list of\n    objects of type ['b] using [f].\n    We obtain [[l1;l2;b&;ln]] where [length l=n] and [li : 'b list].\n    Then, it returns all the ways of picking exactly one element per [li].\n    @since 1.2 "},{"name":"mapi","kind":"Value","desc":"(int -> 'a -> 'b) -> 'a Containers.List.t -> 'b Containers.List.t","info":""},{"name":"mem","kind":"Value","desc":"?eq:('a -> 'a -> bool) -> 'a -> 'a Containers.List.t -> bool","info":" Membership to the list. Linear time "},{"name":"mem_assoc","kind":"Value","desc":"'a -> ('a * 'b) list -> bool","info":" Same as {!List.assoc}, but simply return true if a binding exists,\n   and false if no bindings exist for the given key. "},{"name":"mem_assq","kind":"Value","desc":"'a -> ('a * 'b) list -> bool","info":" Same as {!List.mem_assoc}, but uses physical equality instead of\n   structural equality to compare keys. "},{"name":"memq","kind":"Value","desc":"'a -> 'a list -> bool","info":" Same as {!List.mem}, but uses physical equality instead of structural\n   equality to compare list elements. "},{"name":"merge","kind":"Value","desc":"('a -> 'a -> int) -> 'a list -> 'a list -> 'a list","info":" Merge two lists:\n    Assuming that [l1] and [l2] are sorted according to the\n    comparison function [cmp], [merge cmp l1 l2] will return a\n    sorted list containting all the elements of [l1] and [l2].\n    If several elements compare equal, the elements of [l1] will be\n    before the elements of [l2].\n    Not tail-recursive (sum of the lengths of the arguments).\n"},{"name":"nth","kind":"Value","desc":"'a list -> int -> 'a","info":" Return the [n]-th element of the given list.\n   The first element (head of the list) is at position 0.\n   Raise [Failure \"nth\"] if the list is too short.\n   Raise [Invalid_argument \"List.nth\"] if [n] is negative. "},{"name":"of_gen","kind":"Value","desc":"'a Containers.List.gen -> 'a Containers.List.t","info":""},{"name":"of_klist","kind":"Value","desc":"'a Containers.List.klist -> 'a Containers.List.t","info":""},{"name":"of_seq","kind":"Value","desc":"'a Containers.List.sequence -> 'a Containers.List.t","info":""},{"name":"partition","kind":"Value","desc":"('a -> bool) -> 'a list -> 'a list * 'a list","info":" [partition p l] returns a pair of lists [(l1, l2)], where\n   [l1] is the list of all the elements of [l] that\n   satisfy the predicate [p], and [l2] is the list of all the\n   elements of [l] that do not satisfy [p].\n   The order of the elements in the input list is preserved. "},{"name":"partition_map","kind":"Value","desc":"('a -> [< `Drop | `Left of 'b | `Right of 'c ]) ->\n'a list -> 'b list * 'c list","info":" [partition_map f l] maps [f] on [l] and gather results in lists:\n    - if [f x = `Left y], adds [y] to the first list\n    - if [f x = `Right z], adds [z] to the second list\n    - if [f x = `Drop], ignores [x]\n    @since 0.11 "},{"name":"pp","kind":"Value","desc":"?start:string ->\n?stop:string ->\n?sep:string ->\n'a Containers.List.printer -> 'a Containers.List.t Containers.List.printer","info":""},{"name":"product","kind":"Value","desc":"('a -> 'b -> 'c) ->\n'a Containers.List.t -> 'b Containers.List.t -> 'c Containers.List.t","info":" Cartesian product of the two lists, with the given combinator "},{"name":"pure","kind":"Value","desc":"'a -> 'a Containers.List.t","info":""},{"name":"random","kind":"Value","desc":"'a Containers.List.random_gen ->\n'a Containers.List.t Containers.List.random_gen","info":""},{"name":"random_choose","kind":"Value","desc":"'a Containers.List.t -> 'a Containers.List.random_gen","info":" Randomly choose an element in the list.\n    @raise Not_found if the list is empty "},{"name":"random_len","kind":"Value","desc":"int ->\n'a Containers.List.random_gen ->\n'a Containers.List.t Containers.List.random_gen","info":""},{"name":"random_non_empty","kind":"Value","desc":"'a Containers.List.random_gen ->\n'a Containers.List.t Containers.List.random_gen","info":""},{"name":"random_sequence","kind":"Value","desc":"'a Containers.List.random_gen Containers.List.t ->\n'a Containers.List.t Containers.List.random_gen","info":""},{"name":"range","kind":"Value","desc":"int -> int -> int Containers.List.t","info":" [range i j] iterates on integers from [i] to [j] included . It works\n    both for decreasing and increasing ranges "},{"name":"range'","kind":"Value","desc":"int -> int -> int Containers.List.t","info":" Same as {!range} but the second bound is excluded.\n    For instance [range' 0 5 = [0;1;2;3;4]] "},{"name":"range_by","kind":"Value","desc":"step:int -> int -> int -> int Containers.List.t","info":" [range_by ~step i j] iterates on integers from [i] to [j] included,\n    where the difference between successive elements is [step].\n    use a negative [step] for a decreasing list.\n    @raise Invalid_argument if [step=0]\n    @since 0.18 "},{"name":"remove","kind":"Value","desc":"?eq:('a -> 'a -> bool) ->\nx:'a -> 'a Containers.List.t -> 'a Containers.List.t","info":" [remove ~x l] removes every instance of [x] from [l]. Tailrec.\n    @param eq equality function\n    @since 0.11 "},{"name":"remove_assoc","kind":"Value","desc":"'a -> ('a * 'b) list -> ('a * 'b) list","info":" [remove_assoc a l] returns the list of\n   pairs [l] without the first pair with key [a], if any.\n   Not tail-recursive. "},{"name":"remove_assq","kind":"Value","desc":"'a -> ('a * 'b) list -> ('a * 'b) list","info":" Same as {!List.remove_assoc}, but uses physical equality instead\n   of structural equality to compare keys.  Not tail-recursive. "},{"name":"remove_at_idx","kind":"Value","desc":"int -> 'a Containers.List.t -> 'a Containers.List.t","info":" Remove element at given index. Does nothing if the index is\n    too high. "},{"name":"remove_one","kind":"Value","desc":"?eq:('a -> 'a -> bool) -> 'a -> 'a Containers.List.t -> 'a Containers.List.t","info":" [remove_one x set] removes one occurrence of [x] from [set]. Linear time.\n    @since 0.11 "},{"name":"repeat","kind":"Value","desc":"int -> 'a Containers.List.t -> 'a Containers.List.t","info":" Concatenate the list with itself [n] times "},{"name":"replicate","kind":"Value","desc":"int -> 'a -> 'a Containers.List.t","info":" Replicate the given element [n] times "},{"name":"return","kind":"Value","desc":"'a -> 'a Containers.List.t","info":""},{"name":"rev","kind":"Value","desc":"'a list -> 'a list","info":" List reversal. "},{"name":"rev_append","kind":"Value","desc":"'a list -> 'a list -> 'a list","info":" [List.rev_append l1 l2] reverses [l1] and concatenates it to [l2].\n   This is equivalent to {!List.rev}[ l1 @ l2], but [rev_append] is\n   tail-recursive and more efficient. "},{"name":"rev_map","kind":"Value","desc":"('a -> 'b) -> 'a list -> 'b list","info":" [List.rev_map f l] gives the same result as\n   {!List.rev}[ (]{!List.map}[ f l)], but is tail-recursive and\n   more efficient. "},{"name":"rev_map2","kind":"Value","desc":"('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list","info":" [List.rev_map2 f l1 l2] gives the same result as\n   {!List.rev}[ (]{!List.map2}[ f l1 l2)], but is tail-recursive and\n   more efficient. "},{"name":"scan_left","kind":"Value","desc":"('acc -> 'a -> 'acc) -> 'acc -> 'a list -> 'acc list","info":" [scan_left f acc l] returns the list [[acc; f acc x0; f (f acc x0) x1; b&]]\n    where [x0], [x1], etc. are the elements of [l]\n    @since 1.2 "},{"name":"set_at_idx","kind":"Value","desc":"int -> 'a -> 'a Containers.List.t -> 'a Containers.List.t","info":" Set i-th element (removes the old one), or does nothing if\n    index is too high "},{"name":"sort","kind":"Value","desc":"('a -> 'a -> int) -> 'a list -> 'a list","info":" Sort a list in increasing order according to a comparison\n   function.  The comparison function must return 0 if its arguments\n   compare as equal, a positive integer if the first is greater,\n   and a negative integer if the first is smaller (see Array.sort for\n   a complete specification).  For example,\n   {!Pervasives.compare} is a suitable comparison function.\n   The resulting list is sorted in increasing order.\n   [List.sort] is guaranteed to run in constant heap space\n   (in addition to the size of the result list) and logarithmic\n   stack space.\n\n   The current implementation uses Merge Sort. It runs in constant\n   heap space and logarithmic stack space.\n"},{"name":"sort_uniq","kind":"Value","desc":"?cmp:('a -> 'a -> int) -> 'a list -> 'a list","info":" Sort the list and remove duplicate elements "},{"name":"sorted_insert","kind":"Value","desc":"?cmp:('a -> 'a -> int) -> ?uniq:bool -> 'a -> 'a list -> 'a list","info":" [sorted_insert x l] inserts [x] into [l] such that, if [l] was sorted,\n    then [sorted_insert x l] is sorted too.\n    @param uniq if true and [x] is already in sorted position in [l], then\n      [x] is not duplicated. Default [false] ([x] will be inserted in any case).\n    @since 0.17 "},{"name":"sorted_merge","kind":"Value","desc":"?cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list","info":" Merges elements from both sorted list "},{"name":"sorted_merge_uniq","kind":"Value","desc":"?cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list","info":" [sorted_merge_uniq l1 l2] merges the sorted lists [l1] and [l2] and\n    removes duplicates\n    @since 0.10 "},{"name":"split","kind":"Value","desc":"('a * 'b) list -> 'a list * 'b list","info":" Transform a list of pairs into a pair of lists:\n   [split [(a1,b1); ...; (an,bn)]] is [([a1; ...; an], [b1; ...; bn])].\n   Not tail-recursive.\n"},{"name":"stable_sort","kind":"Value","desc":"('a -> 'a -> int) -> 'a list -> 'a list","info":" Same as {!List.sort}, but the sorting algorithm is guaranteed to\n   be stable (i.e. elements that compare equal are kept in their\n   original order) .\n\n   The current implementation uses Merge Sort. It runs in constant\n   heap space and logarithmic stack space.\n"},{"name":"sublists_of_len","kind":"Value","desc":"?last:('a list -> 'a list option) ->\n?offset:int -> int -> 'a list -> 'a list list","info":" [sublists_of_len n l] returns sub-lists of [l] that have length [n].\n    By default, these sub-lists are non overlapping:\n    [sublists_of_len 2 [1;2;3;4;5;6]] returns [[1;2]; [3;4]; [5;6]]\n\n    Examples:\n\n    - [sublists_of_len 2 [1;2;3;4;5;6] = [[1;2]; [3;4]; [5;6]]]\n    - [sublists_of_len 2 ~offset:3 [1;2;3;4;5;6] = [1;2];[4;5]]\n    - [sublists_of_len 3 ~last:CCOpt.return [1;2;3;4] = [1;2;3];[4]]\n    - [sublists_of_len 2 [1;2;3;4;5] = [[1;2]; [3;4]]]\n\n    @param offset the number of elements skipped between two consecutive\n      sub-lists. By default it is [n]. If [offset < n], the sub-lists\n      will overlap; if [offset > n], some elements will not appear at all.\n    @param last if provided and the last group of elements [g] is such\n      that [length g < n], [last g] is called. If [last g = Some g'],\n      [g'] is appended; otherwise [g] is dropped.\n      If [last = CCOpt.return], it will simply keep the last group.\n      By default, [last = fun _ -> None], i.e. the last group is dropped if shorter than [n].\n    @raise Invalid_argument if [offset <= 0] or [n <= 0]\n    @since 1.0 "},{"name":"subset","kind":"Value","desc":"?eq:('a -> 'a -> bool) ->\n'a Containers.List.t -> 'a Containers.List.t -> bool","info":" Test for inclusion "},{"name":"take","kind":"Value","desc":"int -> 'a Containers.List.t -> 'a Containers.List.t","info":" Take the [n] first elements, drop the rest "},{"name":"take_drop","kind":"Value","desc":"int -> 'a Containers.List.t -> 'a Containers.List.t * 'a Containers.List.t","info":" [take_drop n l] returns [l1, l2] such that [l1 @ l2 = l] and\n    [length l1 = min (length l) n] "},{"name":"take_drop_while","kind":"Value","desc":"('a -> bool) ->\n'a Containers.List.t -> 'a Containers.List.t * 'a Containers.List.t","info":" [take_drop_while p l = take_while p l, drop_while p l]\n    @since 1.2 "},{"name":"take_while","kind":"Value","desc":"('a -> bool) -> 'a Containers.List.t -> 'a Containers.List.t","info":" @since 0.13 "},{"name":"tl","kind":"Value","desc":"'a list -> 'a list","info":" Return the given list without its first element. Raise\n   [Failure \"tl\"] if the list is empty. "},{"name":"to_gen","kind":"Value","desc":"'a Containers.List.t -> 'a Containers.List.gen","info":""},{"name":"to_klist","kind":"Value","desc":"'a Containers.List.t -> 'a Containers.List.klist","info":""},{"name":"to_seq","kind":"Value","desc":"'a Containers.List.t -> 'a Containers.List.sequence","info":""},{"name":"union","kind":"Value","desc":"?eq:('a -> 'a -> bool) ->\n'a Containers.List.t -> 'a Containers.List.t -> 'a Containers.List.t","info":" List union. Complexity is product of length of inputs. "},{"name":"uniq","kind":"Value","desc":"?eq:('a -> 'a -> bool) -> 'a Containers.List.t -> 'a Containers.List.t","info":" Remove duplicates w.r.t the equality predicate.\n    Complexity is quadratic in the length of the list, but the order\n    of elements is preserved. If you wish for a faster de-duplication\n    but do not care about the order, use {!sort_uniq}"},{"name":"uniq_succ","kind":"Value","desc":"?eq:('a -> 'a -> bool) -> 'a list -> 'a list","info":" [uniq_succ l] removes duplicate elements that occur one next to the other.\n    Examples:\n    [uniq_succ [1;2;1] = [1;2;1]]\n    [uniq_succ [1;1;2] = [1;2]]\n    @since 0.10 "},{"name":"gen","kind":"Type","desc":"type 'a gen = unit -> 'a option","info":""},{"name":"klist","kind":"Type","desc":"type 'a klist = unit -> [ `Cons of 'a * 'a Containers.List.klist | `Nil ]","info":""},{"name":"printer","kind":"Type","desc":"type 'a printer = Format.formatter -> 'a -> unit","info":""},{"name":"random_gen","kind":"Type","desc":"type 'a random_gen = Random.State.t -> 'a","info":""},{"name":"sequence","kind":"Type","desc":"type 'a sequence = ('a -> unit) -> unit","info":""},{"name":"t","kind":"Type","desc":"type 'a t = 'a list","info":""},{"name":"Assoc","kind":"Module","desc":"","info":""},{"name":"Infix","kind":"Module","desc":"","info":""},{"name":"Ref","kind":"Module","desc":"","info":""},{"name":"Traverse","kind":"Module","desc":"","info":""},{"name":"MONAD","kind":"Signature","desc":"","info":""}],"context":["application",{"argument_type":"'_a","labels":[]}]}]
hackwaly commented 7 years ago

Couldn't reproduce your problem. Which OS do you use? image

ryanslade commented 7 years ago

I'm running Ubuntu 16.04

VS Code Details:

Version 1.12.2
Commit 19222cdc84ce72202478ba1cec5cb557b71163de
Date 2017-05-10T13:16:25.899Z
Shell 1.6.6
Renderer 56.0.2924.87
Node 7.4.0

OCaml details

ocamlmerlin -version
The Merlin toolkit version 2.5.4, for Ocaml 4.04.1

containers 1.2
hackwaly commented 7 years ago

Try v0.6.29 and check if it fixed.

ryanslade commented 7 years ago

Great, it works! Thanks for the quick fix :+1: