mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	Merge pull request #3270 from ZyX-I/shada-support
Add plugin for editing ShaDa files
This commit is contained in:
		
							
								
								
									
										820
									
								
								runtime/autoload/msgpack.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										820
									
								
								runtime/autoload/msgpack.vim
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,820 @@ | |||||||
|  | if exists('g:loaded_msgpack_autoload') | ||||||
|  |   finish | ||||||
|  | endif | ||||||
|  | let g:loaded_msgpack_autoload = 1 | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Check that given value is an integer. Respects |msgpack-special-dict|. | ||||||
|  | function msgpack#is_int(v) abort | ||||||
|  |   return type(a:v) == type(0) || ( | ||||||
|  |         \type(a:v) == type({}) && get(a:v, '_TYPE') is# v:msgpack_types.integer) | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Check that given value is an unsigned integer. Respects  | ||||||
|  | " |msgpack-special-dict|. | ||||||
|  | function msgpack#is_uint(v) abort | ||||||
|  |   return msgpack#is_int(a:v) && (type(a:v) == type(0) | ||||||
|  |                                 \? a:v >= 0 | ||||||
|  |                                 \: a:v._VAL[0] > 0) | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " True if s:msgpack_init_python() function was already run. | ||||||
|  | let s:msgpack_python_initialized = 0 | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Cached return of s:msgpack_init_python() used when  | ||||||
|  | " s:msgpack_python_initialized is true. | ||||||
|  | let s:msgpack_python_type = 0 | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Create Python functions that are necessary for work. Also defines functions  | ||||||
|  | " s:msgpack_dict_strftime(format, timestamp) and s:msgpack_dict_strptime(format,  | ||||||
|  | " string). | ||||||
|  | " | ||||||
|  | " @return Zero in case no Python is available, empty string if Python-2 is  | ||||||
|  | "         available and string `"3"` if Python-3 is available. | ||||||
|  | function s:msgpack_init_python() abort | ||||||
|  |   if s:msgpack_python_initialized | ||||||
|  |     return s:msgpack_python_type | ||||||
|  |   endif | ||||||
|  |   let s:msgpack_python_initialized = 1 | ||||||
|  |   for suf in ['', '3'] | ||||||
|  |     try | ||||||
|  |       execute 'python' . suf | ||||||
|  |               \. "def shada_dict_strftime():\n" | ||||||
|  |               \. "  import datetime\n" | ||||||
|  |               \. "  import vim\n" | ||||||
|  |               \. "  fmt = vim.eval('a:format')\n" | ||||||
|  |               \. "  timestamp = vim.eval('a:timestamp')\n" | ||||||
|  |               \. "  timestamp = [int(v) for v in timestamp['_VAL']]\n" | ||||||
|  |               \. "  timestamp = timestamp[0] * (timestamp[1] << 62\n" | ||||||
|  |               \. "                              | timestamp[2] << 31\n" | ||||||
|  |               \. "                              | timestamp[3])\n" | ||||||
|  |               \. "  time = datetime.datetime.fromtimestamp(timestamp)\n" | ||||||
|  |               \. "  return time.strftime(fmt)\n" | ||||||
|  |               \. "def shada_dict_strptime():\n" | ||||||
|  |               \. "  import datetime\n" | ||||||
|  |               \. "  import vim\n" | ||||||
|  |               \. "  fmt = vim.eval('a:format')\n" | ||||||
|  |               \. "  timestr = vim.eval('a:string')\n" | ||||||
|  |               \. "  timestamp = datetime.datetime.strptime(timestr, fmt)\n" | ||||||
|  |               \. "  timestamp = int(timestamp.timestamp())\n" | ||||||
|  |               \. "  if timestamp > 2 ** 31:\n" | ||||||
|  |               \. "    tsabs = abs(timestamp)" | ||||||
|  |               \. "    return ('{\"_TYPE\": v:msgpack_types.integer,'\n" | ||||||
|  |               \. "            + '\"_VAL\": [{sign},{v1},{v2},{v3}]}').format(\n" | ||||||
|  |               \. "              sign=1 if timestamp >= 0 else -1,\n" | ||||||
|  |               \. "              v1=((tsabs >> 62) & 0x3),\n" | ||||||
|  |               \. "              v2=((tsabs >> 31) & (2 ** 31 - 1)),\n" | ||||||
|  |               \. "              v3=(tsabs & (2 ** 31 - 1)))\n" | ||||||
|  |               \. "  else:\n" | ||||||
|  |               \. "    return str(timestamp)\n" | ||||||
|  |       execute  "function s:msgpack_dict_strftime(format, timestamp) abort\n" | ||||||
|  |             \. "  return py" . suf . "eval('shada_dict_strftime()')\n" | ||||||
|  |             \. "endfunction\n" | ||||||
|  |             \. "function s:msgpack_dict_strptime(format, string)\n" | ||||||
|  |             \. "  return eval(py" . suf . "eval('shada_dict_strptime()'))\n" | ||||||
|  |             \. "endfunction\n" | ||||||
|  |       let s:msgpack_python_type = suf | ||||||
|  |       return suf | ||||||
|  |     catch | ||||||
|  |       continue | ||||||
|  |     endtry | ||||||
|  |   endfor | ||||||
|  |  | ||||||
|  |   "" | ||||||
|  |   " strftime() function for |msgpack-special-dict| values. | ||||||
|  |   " | ||||||
|  |   " @param[in]  format     String according to which time should be formatted. | ||||||
|  |   " @param[in]  timestamp  Timestamp (seconds since epoch) to format. | ||||||
|  |   " | ||||||
|  |   " @return Formatted timestamp. | ||||||
|  |   " | ||||||
|  |   " @warning Without +python or +python3 this function does not work correctly.  | ||||||
|  |   "          The VimL code contains “reference” implementation which does not  | ||||||
|  |   "          really work because of precision loss. | ||||||
|  |   function s:msgpack_dict_strftime(format, timestamp) | ||||||
|  |     return msgpack#strftime(a:format, +msgpack#int_dict_to_str(a:timestamp)) | ||||||
|  |   endfunction | ||||||
|  |  | ||||||
|  |   "" | ||||||
|  |   " Function that parses given string according to given format. | ||||||
|  |   " | ||||||
|  |   " @param[in]  format  String according to which string was formatted. | ||||||
|  |   " @param[in]  string  Time formatted according to format. | ||||||
|  |   " | ||||||
|  |   " @return Timestamp. | ||||||
|  |   " | ||||||
|  |   " @warning Without +python or +python3 this function is able to work only with  | ||||||
|  |   "          31-bit (32-bit signed) timestamps that have format  | ||||||
|  |   "          `%Y-%m-%dT%H:%M:%S`. | ||||||
|  |   function s:msgpack_dict_strptime(format, string) | ||||||
|  |     let fmt = '%Y-%m-%dT%H:%M:%S' | ||||||
|  |     if a:format isnot# fmt | ||||||
|  |       throw 'notimplemented-format:Only ' . fmt . ' format is supported' | ||||||
|  |     endif | ||||||
|  |     let match = matchlist(a:string, | ||||||
|  |                          \'\v\C^(\d+)\-(\d+)\-(\d+)T(\d+)\:(\d+)\:(\d+)$') | ||||||
|  |     if empty(match) | ||||||
|  |       throw 'invalid-string:Given string does not match format ' . a:format | ||||||
|  |     endif | ||||||
|  |     call map(match, 'str2nr(v:val, 10)') | ||||||
|  |     let [year, month, day, hour, minute, second] = match[1:6] | ||||||
|  |     " Bisection start and end: | ||||||
|  |     " | ||||||
|  |     " Start: 365 days in year, 28 days in month, -12 hours tz offset. | ||||||
|  |     let bisect_ts_start = (((((year - 1970) * 365 | ||||||
|  |                              \+ (month - 1) * 28 | ||||||
|  |                              \+ (day - 1)) * 24 | ||||||
|  |                             \+ hour - 12) * 60 | ||||||
|  |                            \+ minute) * 60 | ||||||
|  |                           \+ second) | ||||||
|  |     if bisect_ts_start < 0 | ||||||
|  |       let bisect_ts_start = 0 | ||||||
|  |     endif | ||||||
|  |     let start_string = strftime(fmt, bisect_ts_start) | ||||||
|  |     if start_string is# a:string | ||||||
|  |       return bisect_ts_start | ||||||
|  |     endif | ||||||
|  |     " End: 366 days in year, 31 day in month, +14 hours tz offset. | ||||||
|  |     let bisect_ts_end = (((((year - 1970) * 366 | ||||||
|  |                            \+ (month - 1) * 31 | ||||||
|  |                            \+ (day - 1)) * 24 | ||||||
|  |                           \+ hour + 14) * 60 | ||||||
|  |                          \+ minute) * 60 | ||||||
|  |                         \+ second) | ||||||
|  |     let end_string = strftime(fmt, bisect_ts_end) | ||||||
|  |     if end_string is# a:string | ||||||
|  |       return bisect_ts_end | ||||||
|  |     endif | ||||||
|  |     if start_string ># end_string | ||||||
|  |       throw 'internal-start-gt:Internal error: start > end' | ||||||
|  |     endif | ||||||
|  |     if start_string is# end_string | ||||||
|  |       throw printf('internal-start-eq:Internal error: ' | ||||||
|  |                   \. 'start(%u)==end(%u), but start(%s)!=string(%s)', | ||||||
|  |                   \bisect_ts_start, bisect_ts_end, | ||||||
|  |                   \string(start_string), string(a:string)) | ||||||
|  |     endif | ||||||
|  |     if start_string ># a:string | ||||||
|  |       throw 'internal-start-string:Internal error: start > string' | ||||||
|  |     endif | ||||||
|  |     if end_string <# a:string | ||||||
|  |       throw 'internal-end-string:Internal error: end < string' | ||||||
|  |     endif | ||||||
|  |     while 1 | ||||||
|  |       let bisect_ts_middle = (bisect_ts_start/2) + (bisect_ts_end/2) | ||||||
|  |       let middle_string = strftime(fmt, bisect_ts_middle) | ||||||
|  |       if a:string is# middle_string | ||||||
|  |         return bisect_ts_middle | ||||||
|  |       elseif a:string ># middle_string | ||||||
|  |         if bisect_ts_middle == bisect_ts_start | ||||||
|  |           let bisect_ts_start += 1 | ||||||
|  |         else | ||||||
|  |           let bisect_ts_start = bisect_ts_middle | ||||||
|  |         endif | ||||||
|  |       else | ||||||
|  |         if bisect_ts_middle == bisect_ts_end | ||||||
|  |           let bisect_ts_end -= 1 | ||||||
|  |         else | ||||||
|  |           let bisect_ts_end = bisect_ts_middle | ||||||
|  |         endif | ||||||
|  |       endif | ||||||
|  |       if bisect_ts_start >= bisect_ts_end | ||||||
|  |         throw 'not-found:Unable to find timestamp' | ||||||
|  |       endif | ||||||
|  |     endwhile | ||||||
|  |   endfunction | ||||||
|  |  | ||||||
|  |   return 0 | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Wrapper for strftime() that respects |msgpack-special-dict|. May actually use  | ||||||
|  | " non-standard strftime() implementations for |msgpack-special-dict| values. | ||||||
|  | " | ||||||
|  | " @param[in]  format     Format string. | ||||||
|  | " @param[in]  timestamp  Formatted timestamp. | ||||||
|  | function msgpack#strftime(format, timestamp) abort | ||||||
|  |   if type(a:timestamp) == type({}) | ||||||
|  |     call s:msgpack_init_python() | ||||||
|  |     return s:msgpack_dict_strftime(a:format, a:timestamp) | ||||||
|  |   else | ||||||
|  |     return strftime(a:format, a:timestamp) | ||||||
|  |   endif | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Parse string according to the format. | ||||||
|  | " | ||||||
|  | " Requires +python available. If it is not then only supported format is  | ||||||
|  | " `%Y-%m-%dT%H:%M:%S` because this is the format used by ShaDa plugin. Also in  | ||||||
|  | " this case bisection will be used (timestamps tried with strftime() up until  | ||||||
|  | " result matches the string) and only 31-bit (signed 32-bit: with negative  | ||||||
|  | " timestamps being useless this leaves 31 bits) timestamps will be supported. | ||||||
|  | " | ||||||
|  | " @param[in]  format  Time format. | ||||||
|  | " @param[in]  string  Parsed time string. Must match given format. | ||||||
|  | " | ||||||
|  | " @return Timestamp. Possibly as |msgpack-special-dict|. | ||||||
|  | function msgpack#strptime(format, string) abort | ||||||
|  |   call s:msgpack_init_python() | ||||||
|  |   return s:msgpack_dict_strptime(a:format, a:string) | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | let s:MSGPACK_HIGHEST_BIT = 1 | ||||||
|  | let s:MSGPACK_HIGHEST_BIT_NR = 0 | ||||||
|  | while s:MSGPACK_HIGHEST_BIT * 2 > 0 | ||||||
|  |   let s:MSGPACK_HIGHEST_BIT = s:MSGPACK_HIGHEST_BIT * 2 | ||||||
|  |   let s:MSGPACK_HIGHEST_BIT_NR += 1 | ||||||
|  | endwhile | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Shift given number by given amount of bits | ||||||
|  | function s:shift(n, s) abort | ||||||
|  |   if a:s == 0 | ||||||
|  |     return a:n | ||||||
|  |   elseif a:s < 0 | ||||||
|  |     let ret = a:n | ||||||
|  |     for _ in range(-a:s) | ||||||
|  |       let ret = ret / 2 | ||||||
|  |     endfor | ||||||
|  |     return ret | ||||||
|  |   else | ||||||
|  |     let ret = a:n | ||||||
|  |     for i in range(a:s) | ||||||
|  |       let new_ret = ret * 2 | ||||||
|  |       if new_ret < ret | ||||||
|  |         " Overflow: remove highest bit | ||||||
|  |         let ret = xor(s:MSGPACK_HIGHEST_BIT, ret) * 2 | ||||||
|  |       endif | ||||||
|  |       let ret = new_ret | ||||||
|  |     endfor | ||||||
|  |     return ret | ||||||
|  |   endif | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | let s:msgpack_mask_cache = { | ||||||
|  |       \s:MSGPACK_HIGHEST_BIT_NR : s:MSGPACK_HIGHEST_BIT - 1} | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Apply a mask where first m bits are ones and other are zeroes to a given  | ||||||
|  | " number | ||||||
|  | function s:mask1(n, m) abort | ||||||
|  |   if a:m > s:MSGPACK_HIGHEST_BIT_NR + 1 | ||||||
|  |     let m = s:MSGPACK_HIGHEST_BIT_NR + 1 | ||||||
|  |   else | ||||||
|  |     let m = a:m | ||||||
|  |   endif | ||||||
|  |   if !has_key(s:msgpack_mask_cache, m) | ||||||
|  |     let p = 0 | ||||||
|  |     for _ in range(m) | ||||||
|  |       let p = p * 2 + 1 | ||||||
|  |     endfor | ||||||
|  |     let s:msgpack_mask_cache[m] = p | ||||||
|  |   endif | ||||||
|  |   return and(a:n, s:msgpack_mask_cache[m]) | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert |msgpack-special-dict| that represents integer value to a string. Uses  | ||||||
|  | " hexadecimal representation starting with 0x because it is the easiest to  | ||||||
|  | " convert to. | ||||||
|  | function msgpack#int_dict_to_str(v) abort | ||||||
|  |   let v = a:v._VAL | ||||||
|  |   " 64-bit number: | ||||||
|  |   " 0000000001111111111222222222233333333334444444444555555555566666 | ||||||
|  |   " 1234567890123456789012345678901234567890123456789012345678901234 | ||||||
|  |   " Split in _VAL: | ||||||
|  |   " 0000000001111111111222222222233 3333333344444444445555555555666 66 | ||||||
|  |   " 1234567890123456789012345678901 2345678901234567890123456789012 34 | ||||||
|  |   " Split by hex digits: | ||||||
|  |   " 0000 0000 0111 1111 1112 2222 2222 2333 3333 3334 4444 4444 4555 5555 5556 6666 | ||||||
|  |   " 1234 5678 9012 3456 7890 1234 5678 9012 3456 7890 1234 5678 9012 3456 7890 1234 | ||||||
|  |   " | ||||||
|  |   " Total split: | ||||||
|  |   "                _VAL[3]                              _VAL[2]                      _VAL[1] | ||||||
|  |   " ______________________________________  _______________________________________  __ | ||||||
|  |   " 0000 0000 0111 1111 1112 2222 2222 233  3 3333 3334 4444 4444 4555 5555 5556 66  66 | ||||||
|  |   " 1234 5678 9012 3456 7890 1234 5678 901  2 3456 7890 1234 5678 9012 3456 7890 12  34 | ||||||
|  |   " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ | ||||||
|  |   "                g4                    g3                  g2                    g1 | ||||||
|  |   " ********************************** ***  * ********************************** **  ** | ||||||
|  |   "                1                    2   3                4                   5   6 | ||||||
|  |   " 1: s:mask1(v[3], 28): first 28 bits of _VAL[3] | ||||||
|  |   " 2: s:shift(v[3], -28): last 3 bits of _VAL[3] | ||||||
|  |   " 3: s:mask1(v[2], 1): first bit of _VAL[2] | ||||||
|  |   " 4: s:mask1(s:shift(v[2], -1), 28): bits 2 .. 29 of _VAL[2] | ||||||
|  |   " 5: s:shift(v[2], -29): last 2 bits of _VAL[2] | ||||||
|  |   " 6: s:shift(v[1], 2): _VAL[1] | ||||||
|  |   let g4 = printf('%07x', s:mask1(v[3], 28)) | ||||||
|  |   let g3 = printf('%01x', or(s:shift(v[3], -28), s:shift(s:mask1(v[2], 1), 3))) | ||||||
|  |   let g2 = printf('%07x', s:mask1(s:shift(v[2], -1), 28)) | ||||||
|  |   let g1 = printf('%01x', or(s:shift(v[2], -29), s:shift(v[1], 2))) | ||||||
|  |   return ((v[0] < 0 ? '-' : '') . '0x' . g1 . g2 . g3 . g4) | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " True boolean value. | ||||||
|  | let g:msgpack#true = {'_TYPE': v:msgpack_types.boolean, '_VAL': 1} | ||||||
|  | lockvar! g:msgpack#true | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " False boolean value. | ||||||
|  | let g:msgpack#false = {'_TYPE': v:msgpack_types.boolean, '_VAL': 0} | ||||||
|  | lockvar! g:msgpack#false | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " NIL value. | ||||||
|  | let g:msgpack#nil = {'_TYPE': v:msgpack_types.nil, '_VAL': 0} | ||||||
|  | lockvar! g:msgpack#nil | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Deduce type of |msgpack-special-dict|. | ||||||
|  | " | ||||||
|  | " @return zero if given dictionary is not special or name of the key in  | ||||||
|  | "         v:msgpack_types dictionary. | ||||||
|  | function msgpack#special_type(v) abort | ||||||
|  |   if type(a:v) != type({}) || !has_key(a:v, '_TYPE') | ||||||
|  |     return 0 | ||||||
|  |   endif | ||||||
|  |   for [k, v] in items(v:msgpack_types) | ||||||
|  |     if a:v._TYPE is v | ||||||
|  |       return k | ||||||
|  |     endif | ||||||
|  |   endfor | ||||||
|  |   return 0 | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Mapping that maps type() output to type names. | ||||||
|  | let s:MSGPACK_STANDARD_TYPES = { | ||||||
|  |   \type(0): 'integer', | ||||||
|  |   \type(0.0): 'float', | ||||||
|  |   \type(''): 'binary', | ||||||
|  |   \type([]): 'array', | ||||||
|  |   \type({}): 'map', | ||||||
|  | \} | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Deduce type of one of items returned by msgpackparse(). | ||||||
|  | " | ||||||
|  | " @return Name of a key in v:msgpack_types. | ||||||
|  | function msgpack#type(v) abort | ||||||
|  |   let special_type = msgpack#special_type(a:v) | ||||||
|  |   if special_type is 0 | ||||||
|  |     return s:MSGPACK_STANDARD_TYPES[type(a:v)] | ||||||
|  |   endif | ||||||
|  |   return special_type | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dump nil value. | ||||||
|  | function s:msgpack_dump_nil(v) abort | ||||||
|  |   return 'NIL' | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dump boolean value. | ||||||
|  | function s:msgpack_dump_boolean(v) abort | ||||||
|  |   return a:v._VAL ? 'TRUE' : 'FALSE' | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dump integer msgpack value. | ||||||
|  | function s:msgpack_dump_integer(v) abort | ||||||
|  |   if type(a:v) == type({}) | ||||||
|  |     return msgpack#int_dict_to_str(a:v) | ||||||
|  |   else | ||||||
|  |     return string(a:v) | ||||||
|  |   endif | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dump floating-point value. | ||||||
|  | function s:msgpack_dump_float(v) abort | ||||||
|  |   return string(type(a:v) == type({}) ? a:v._VAL : a:v) | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dump |msgpack-special-dict| that represents a string. If any additional  | ||||||
|  | " parameter is given then it dumps binary string. | ||||||
|  | function s:msgpack_dump_string(v, ...) abort | ||||||
|  |   let ret = [a:0 ? '"' : '="'] | ||||||
|  |   for v in a:v._VAL | ||||||
|  |     call add( | ||||||
|  |           \ret, | ||||||
|  |           \substitute( | ||||||
|  |             \substitute(v, '["\\]', '\\\0', 'g'), | ||||||
|  |             \'\n', '\\0', 'g')) | ||||||
|  |     call add(ret, '\n') | ||||||
|  |   endfor | ||||||
|  |   let ret[-1] = '"' | ||||||
|  |   return join(ret, '') | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dump binary string. | ||||||
|  | function s:msgpack_dump_binary(v) abort | ||||||
|  |   if type(a:v) == type({}) | ||||||
|  |     return s:msgpack_dump_string(a:v, 1) | ||||||
|  |   else | ||||||
|  |     return s:msgpack_dump_string({'_VAL': split(a:v, "\n", 1)}, 1) | ||||||
|  |   endif | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dump array value. | ||||||
|  | function s:msgpack_dump_array(v) abort | ||||||
|  |   let val = type(a:v) == type({}) ? a:v._VAL : a:v | ||||||
|  |   return '[' . join(map(val[:], 'msgpack#string(v:val)'), ', ') . ']' | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dump dictionary value. | ||||||
|  | function s:msgpack_dump_map(v) abort | ||||||
|  |   let ret = ['{'] | ||||||
|  |   if msgpack#special_type(a:v) is 0 | ||||||
|  |     for [k, v] in items(a:v) | ||||||
|  |       let ret += [s:msgpack_dump_string({'_VAL': split(k, "\n", 1)}), | ||||||
|  |                  \': ', | ||||||
|  |                  \msgpack#string(v), | ||||||
|  |                  \', '] | ||||||
|  |       unlet v | ||||||
|  |     endfor | ||||||
|  |     if !empty(a:v) | ||||||
|  |       call remove(ret, -1) | ||||||
|  |     endif | ||||||
|  |   else | ||||||
|  |     for [k, v] in sort(copy(a:v._VAL)) | ||||||
|  |       let ret += [msgpack#string(k), | ||||||
|  |                  \': ', | ||||||
|  |                  \msgpack#string(v), | ||||||
|  |                  \', '] | ||||||
|  |       unlet k | ||||||
|  |       unlet v | ||||||
|  |     endfor | ||||||
|  |     if !empty(a:v._VAL) | ||||||
|  |       call remove(ret, -1) | ||||||
|  |     endif | ||||||
|  |   endif | ||||||
|  |   let ret += ['}'] | ||||||
|  |   return join(ret, '') | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dump extension value. | ||||||
|  | function s:msgpack_dump_ext(v) abort | ||||||
|  |   return printf('+(%i)%s', a:v._VAL[0], | ||||||
|  |                \s:msgpack_dump_string({'_VAL': a:v._VAL[1]}, 1)) | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert msgpack object to a string, like string() function does. Result of the  | ||||||
|  | " conversion may be passed to msgpack#eval(). | ||||||
|  | function msgpack#string(v) abort | ||||||
|  |   if type(a:v) == type({}) | ||||||
|  |     let type = msgpack#special_type(a:v) | ||||||
|  |     if type is 0 | ||||||
|  |       let type = 'map' | ||||||
|  |     endif | ||||||
|  |   else | ||||||
|  |     let type = get(s:MSGPACK_STANDARD_TYPES, type(a:v), 0) | ||||||
|  |     if type is 0 | ||||||
|  |       throw printf('msgpack:invtype: Unable to convert value %s', string(a:v)) | ||||||
|  |     endif | ||||||
|  |   endif | ||||||
|  |   return s:msgpack_dump_{type}(a:v) | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Copy msgpack object like deepcopy() does, but leave types intact | ||||||
|  | function msgpack#deepcopy(obj) abort | ||||||
|  |   if type(a:obj) == type([]) | ||||||
|  |     return map(copy(a:obj), 'msgpack#deepcopy(v:val)') | ||||||
|  |   elseif type(a:obj) == type({}) | ||||||
|  |     let special_type = msgpack#special_type(a:obj) | ||||||
|  |     if special_type is 0 | ||||||
|  |       return map(copy(a:obj), 'msgpack#deepcopy(v:val)') | ||||||
|  |     else | ||||||
|  |       return { | ||||||
|  |         \'_TYPE': v:msgpack_types[special_type], | ||||||
|  |         \'_VAL': msgpack#deepcopy(a:obj._VAL) | ||||||
|  |       \} | ||||||
|  |     endif | ||||||
|  |   else | ||||||
|  |     return copy(a:obj) | ||||||
|  |   endif | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert an escaped character to needed value | ||||||
|  | function s:msgpack_eval_str_sub(ch) abort | ||||||
|  |   if a:ch is# 'n' | ||||||
|  |     return '", "' | ||||||
|  |   elseif a:ch is# '0' | ||||||
|  |     return '\n' | ||||||
|  |   else | ||||||
|  |     return '\' . a:ch | ||||||
|  |   endif | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | let s:MSGPACK_SPECIAL_OBJECTS = { | ||||||
|  |   \'NIL': '{''_TYPE'': v:msgpack_types.nil, ''_VAL'': 0}', | ||||||
|  |   \'TRUE': '{''_TYPE'': v:msgpack_types.boolean, ''_VAL'': 1}', | ||||||
|  |   \'FALSE': '{''_TYPE'': v:msgpack_types.boolean, ''_VAL'': 0}', | ||||||
|  |   \'nan': '(-(1.0/0.0-1.0/0.0))', | ||||||
|  |   \'inf': '(1.0/0.0)', | ||||||
|  | \} | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert msgpack object dumped by msgpack#string() to a VimL object suitable  | ||||||
|  | " for msgpackdump(). | ||||||
|  | " | ||||||
|  | " @param[in]  s             String to evaluate. | ||||||
|  | " @param[in]  special_objs  Additional special objects, in the same format as  | ||||||
|  | "                           s:MSGPACK_SPECIAL_OBJECTS. | ||||||
|  | " | ||||||
|  | " @return Any value that msgpackparse() may return. | ||||||
|  | function msgpack#eval(s, special_objs) abort | ||||||
|  |   let s = a:s | ||||||
|  |   let expr = [] | ||||||
|  |   let context = [] | ||||||
|  |   while !empty(s) | ||||||
|  |     let s = substitute(s, '^\s*', '', '') | ||||||
|  |     if s[0] =~# '\v^\h$' | ||||||
|  |       let name = matchstr(s, '\v\C^\w+') | ||||||
|  |       if has_key(s:MSGPACK_SPECIAL_OBJECTS, name) | ||||||
|  |         call add(expr, s:MSGPACK_SPECIAL_OBJECTS[name]) | ||||||
|  |       elseif has_key(a:special_objs, name) | ||||||
|  |         call add(expr, a:special_objs[name]) | ||||||
|  |       else | ||||||
|  |         throw 'name-unknown:Unknown name ' . name . ': ' . s | ||||||
|  |       endif | ||||||
|  |       let s = s[len(name):] | ||||||
|  |     elseif (s[0] is# '-' && s[1] =~# '\v^\d$') || s[0] =~# '\v^\d$' | ||||||
|  |       let sign = 1 | ||||||
|  |       if s[0] is# '-' | ||||||
|  |         let s = s[1:] | ||||||
|  |         let sign = -1 | ||||||
|  |       endif | ||||||
|  |       if s[0:1] is# '0x' | ||||||
|  |         " See comment in msgpack#int_dict_to_str(). | ||||||
|  |         let s = s[2:] | ||||||
|  |         let hexnum = matchstr(s, '\v\C^\x+') | ||||||
|  |         if empty(hexnum) | ||||||
|  |           throw '0x-empty:Must have number after 0x: ' . s | ||||||
|  |         elseif len(hexnum) > 16 | ||||||
|  |           throw '0x-long:Must have at most 16 hex digits: ' . s | ||||||
|  |         endif | ||||||
|  |         let s = s[len(hexnum):] | ||||||
|  |         let hexnum = repeat('0', 16 - len(hexnum)) . hexnum | ||||||
|  |         let g1 = str2nr(hexnum[0], 16) | ||||||
|  |         let g2 = str2nr(hexnum[1:7], 16) | ||||||
|  |         let g3 = str2nr(hexnum[8], 16) | ||||||
|  |         let g4 = str2nr(hexnum[9:15], 16) | ||||||
|  |         let v1 = s:shift(g1, -2) | ||||||
|  |         let v2 = or(or(s:shift(s:mask1(g1, 2), 29), s:shift(g2, 1)), | ||||||
|  |                    \s:mask1(s:shift(g3, -3), 1)) | ||||||
|  |         let v3 = or(s:shift(s:mask1(g3, 3), 28), g4) | ||||||
|  |         call add(expr, printf('{''_TYPE'': v:msgpack_types.integer, '. | ||||||
|  |                              \'''_VAL'': [%i, %u, %u, %u]}', | ||||||
|  |                              \sign, v1, v2, v3)) | ||||||
|  |       else | ||||||
|  |         let num = matchstr(s, '\v\C^\d+') | ||||||
|  |         let s = s[len(num):] | ||||||
|  |         if sign == -1 | ||||||
|  |           call add(expr, '-') | ||||||
|  |         endif | ||||||
|  |         call add(expr, num) | ||||||
|  |         if s[0] is# '.' | ||||||
|  |           let dec = matchstr(s, '\v\C^\.\d+%(e[+-]?\d+)?') | ||||||
|  |           if empty(dec) | ||||||
|  |             throw '0.-nodigits:Decimal dot must be followed by digit(s): ' . s | ||||||
|  |           endif | ||||||
|  |           let s = s[len(dec):] | ||||||
|  |           call add(expr, dec) | ||||||
|  |         endif | ||||||
|  |       endif | ||||||
|  |     elseif s =~# '-\?\%(inf\|nan\)' | ||||||
|  |       if s[0] is# '-' | ||||||
|  |         call add(expr, '-') | ||||||
|  |         let s = s[1:] | ||||||
|  |       endif | ||||||
|  |       call add(expr, s:MSGPACK_SPECIAL_OBJECTS[s[0:2]]) | ||||||
|  |       let s = s[3:] | ||||||
|  |     elseif stridx('="+', s[0]) != -1 | ||||||
|  |       let match = matchlist(s, '\v\C^(\=|\+\((\-?\d+)\)|)(\"%(\\.|[^\\"]+)*\")') | ||||||
|  |       if empty(match) | ||||||
|  |         throw '"-invalid:Invalid string: ' . s | ||||||
|  |       endif | ||||||
|  |       call add(expr, '{''_TYPE'': v:msgpack_types.') | ||||||
|  |       if empty(match[1]) | ||||||
|  |         call add(expr, 'binary') | ||||||
|  |       elseif match[1] is# '=' | ||||||
|  |         call add(expr, 'string') | ||||||
|  |       else | ||||||
|  |         call add(expr, 'ext') | ||||||
|  |       endif | ||||||
|  |       call add(expr, ', ''_VAL'': [') | ||||||
|  |       if match[1][0] is# '+' | ||||||
|  |         call add(expr, match[2] . ', [') | ||||||
|  |       endif | ||||||
|  |       call add(expr, substitute(match[3], '\v\C\\(.)', | ||||||
|  |                                \'\=s:msgpack_eval_str_sub(submatch(1))', 'g')) | ||||||
|  |       if match[1][0] is# '+' | ||||||
|  |         call add(expr, ']') | ||||||
|  |       endif | ||||||
|  |       call add(expr, ']}') | ||||||
|  |       let s = s[len(match[0]):] | ||||||
|  |     elseif s[0] is# '{' | ||||||
|  |       call add(context, 'map') | ||||||
|  |       call add(expr, '{''_TYPE'': v:msgpack_types.map, ''_VAL'': [') | ||||||
|  |       call add(expr, '[') | ||||||
|  |       let s = s[1:] | ||||||
|  |     elseif s[0] is# '[' | ||||||
|  |       call add(context, 'array') | ||||||
|  |       call add(expr, '[') | ||||||
|  |       let s = s[1:] | ||||||
|  |     elseif s[0] is# ':' | ||||||
|  |       call add(expr, ',') | ||||||
|  |       let s = s[1:] | ||||||
|  |     elseif s[0] is# ',' | ||||||
|  |       if context[-1] is# 'array' | ||||||
|  |         call add(expr, ',') | ||||||
|  |       else | ||||||
|  |         call add(expr, '], [') | ||||||
|  |       endif | ||||||
|  |       let s = s[1:] | ||||||
|  |     elseif s[0] is# ']' | ||||||
|  |       call remove(context, -1) | ||||||
|  |       call add(expr, ']') | ||||||
|  |       let s = s[1:] | ||||||
|  |     elseif s[0] is# '}' | ||||||
|  |       call remove(context, -1) | ||||||
|  |       if expr[-1] is# "\x5B" | ||||||
|  |         call remove(expr, -1) | ||||||
|  |       else | ||||||
|  |         call add(expr, ']') | ||||||
|  |       endif | ||||||
|  |       call add(expr, ']}') | ||||||
|  |       let s = s[1:] | ||||||
|  |     elseif s[0] is# '''' | ||||||
|  |       let char = matchstr(s, '\m\C^''\zs.\ze''') | ||||||
|  |       if empty(char) | ||||||
|  |         throw 'char-invalid:Invalid integer character literal format: ' . s | ||||||
|  |       endif | ||||||
|  |       call add(expr, char2nr(char)) | ||||||
|  |       let s = s[len(char) + 2:] | ||||||
|  |     else | ||||||
|  |       throw 'unknown:Invalid non-space character: ' . s | ||||||
|  |     endif | ||||||
|  |   endwhile | ||||||
|  |   if empty(expr) | ||||||
|  |     throw 'empty:Parsed string is empty' | ||||||
|  |   endif | ||||||
|  |   return eval(join(expr, '')) | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Check whether two msgpack values are equal | ||||||
|  | function msgpack#equal(a, b) | ||||||
|  |   let atype = msgpack#type(a:a) | ||||||
|  |   let btype = msgpack#type(a:b) | ||||||
|  |   if atype isnot# btype | ||||||
|  |     return 0 | ||||||
|  |   endif | ||||||
|  |   let aspecial = msgpack#special_type(a:a) | ||||||
|  |   let bspecial = msgpack#special_type(a:b) | ||||||
|  |   if aspecial is# bspecial | ||||||
|  |     if aspecial is# 0 | ||||||
|  |       if type(a:a) == type({}) | ||||||
|  |         if len(a:a) != len(a:b) | ||||||
|  |           return 0 | ||||||
|  |         endif | ||||||
|  |         if !empty(filter(keys(a:a), '!has_key(a:b, v:val)')) | ||||||
|  |           return 0 | ||||||
|  |         endif | ||||||
|  |         for [k, v] in items(a:a) | ||||||
|  |           if !msgpack#equal(v, a:b[k]) | ||||||
|  |             return 0 | ||||||
|  |           endif | ||||||
|  |           unlet v | ||||||
|  |         endfor | ||||||
|  |         return 1 | ||||||
|  |       elseif type(a:a) == type([]) | ||||||
|  |         if len(a:a) != len(a:b) | ||||||
|  |           return 0 | ||||||
|  |         endif | ||||||
|  |         let i = 0 | ||||||
|  |         for asubval in a:a | ||||||
|  |           if !msgpack#equal(asubval, a:b[i]) | ||||||
|  |             return 0 | ||||||
|  |           endif | ||||||
|  |           let i += 1 | ||||||
|  |           unlet asubval | ||||||
|  |         endfor | ||||||
|  |         return 1 | ||||||
|  |       elseif type(a:a) == type(0.0) | ||||||
|  |         return (a:a == a:a ? a:a == a:b : string(a:a) ==# string(a:b)) | ||||||
|  |       else | ||||||
|  |         return a:a ==# a:b | ||||||
|  |       endif | ||||||
|  |     elseif aspecial is# 'map' || aspecial is# 'array' | ||||||
|  |       if len(a:a._VAL) != len(a:b._VAL) | ||||||
|  |         return 0 | ||||||
|  |       endif | ||||||
|  |       let alist = aspecial is# 'map' ? sort(copy(a:a._VAL)) : a:a._VAL | ||||||
|  |       let blist = bspecial is# 'map' ? sort(copy(a:b._VAL)) : a:b._VAL | ||||||
|  |       let i = 0 | ||||||
|  |       for asubval in alist | ||||||
|  |         let bsubval = blist[i] | ||||||
|  |         if aspecial is# 'map' | ||||||
|  |           if !(msgpack#equal(asubval[0], bsubval[0]) | ||||||
|  |               \&& msgpack#equal(asubval[1], bsubval[1])) | ||||||
|  |             return 0 | ||||||
|  |           endif | ||||||
|  |         else | ||||||
|  |           if !msgpack#equal(asubval, bsubval) | ||||||
|  |             return 0 | ||||||
|  |           endif | ||||||
|  |         endif | ||||||
|  |         let i += 1 | ||||||
|  |         unlet asubval | ||||||
|  |         unlet bsubval | ||||||
|  |       endfor | ||||||
|  |       return 1 | ||||||
|  |     elseif aspecial is# 'nil' | ||||||
|  |       return 1 | ||||||
|  |     elseif aspecial is# 'float' | ||||||
|  |       return (a:a._VAL == a:a._VAL | ||||||
|  |              \? (a:a._VAL == a:b._VAL) | ||||||
|  |              \: (string(a:a._VAL) ==# string(a:b._VAL))) | ||||||
|  |     else | ||||||
|  |       return a:a._VAL ==# a:b._VAL | ||||||
|  |     endif | ||||||
|  |   else | ||||||
|  |     if atype is# 'array' | ||||||
|  |       let a = aspecial is 0 ? a:a : a:a._VAL | ||||||
|  |       let b = bspecial is 0 ? a:b : a:b._VAL | ||||||
|  |       return msgpack#equal(a, b) | ||||||
|  |     elseif atype is# 'binary' | ||||||
|  |       let a = (aspecial is 0 ? split(a:a, "\n", 1) : a:a._VAL) | ||||||
|  |       let b = (bspecial is 0 ? split(a:b, "\n", 1) : a:b._VAL) | ||||||
|  |       return a ==# b | ||||||
|  |     elseif atype is# 'map' | ||||||
|  |       if aspecial is 0 | ||||||
|  |         let akeys = copy(a:a) | ||||||
|  |         if len(a:b._VAL) != len(akeys) | ||||||
|  |           return 0 | ||||||
|  |         endif | ||||||
|  |         for [k, v] in a:b._VAL | ||||||
|  |           if msgpack#type(k) isnot# 'string' | ||||||
|  |             " Non-special mapping cannot have non-string keys | ||||||
|  |             return 0 | ||||||
|  |           endif | ||||||
|  |           if (empty(k._VAL) | ||||||
|  |              \|| k._VAL ==# [""] | ||||||
|  |              \|| !empty(filter(copy(k._VAL), 'stridx(v:val, "\n") != -1'))) | ||||||
|  |             " Non-special mapping cannot have zero byte in key or an empty key | ||||||
|  |             return 0 | ||||||
|  |           endif | ||||||
|  |           let kstr = join(k._VAL, "\n") | ||||||
|  |           if !has_key(akeys, kstr) | ||||||
|  |             " Protects from both missing and duplicate keys | ||||||
|  |             return 0 | ||||||
|  |           endif | ||||||
|  |           if !msgpack#equal(akeys[kstr], v) | ||||||
|  |             return 0 | ||||||
|  |           endif | ||||||
|  |           call remove(akeys, kstr) | ||||||
|  |           unlet k | ||||||
|  |           unlet v | ||||||
|  |         endfor | ||||||
|  |         return 1 | ||||||
|  |       else | ||||||
|  |         return msgpack#equal(a:b, a:a) | ||||||
|  |       endif | ||||||
|  |     elseif atype is# 'float' | ||||||
|  |       let a = aspecial is 0 ? a:a : a:a._VAL | ||||||
|  |       let b = bspecial is 0 ? a:b : a:b._VAL | ||||||
|  |       return (a == a ? a == b : string(a) ==# string(b)) | ||||||
|  |     elseif atype is# 'integer' | ||||||
|  |       if aspecial is 0 | ||||||
|  |         let sign = a:a >= 0 ? 1 : -1 | ||||||
|  |         let a = sign * a:a | ||||||
|  |         let v1 = s:mask1(s:shift(a, -62), 2) | ||||||
|  |         let v2 = s:mask1(s:shift(a, -31), 31) | ||||||
|  |         let v3 = s:mask1(a, 31) | ||||||
|  |         return [sign, v1, v2, v3] == a:b._VAL | ||||||
|  |       else | ||||||
|  |         return msgpack#equal(a:b, a:a) | ||||||
|  |       endif | ||||||
|  |     else | ||||||
|  |       throw printf('internal-invalid-type: %s == %s, but special %s /= %s', | ||||||
|  |                   \atype, btype, aspecial, bspecial) | ||||||
|  |     endif | ||||||
|  |   endif | ||||||
|  | endfunction | ||||||
							
								
								
									
										694
									
								
								runtime/autoload/shada.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										694
									
								
								runtime/autoload/shada.vim
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,694 @@ | |||||||
|  | if exists('g:loaded_shada_autoload') | ||||||
|  |   finish | ||||||
|  | endif | ||||||
|  | let g:loaded_shada_autoload = 1 | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " If true keep the old header entry when editing existing ShaDa file. | ||||||
|  | " | ||||||
|  | " Old header entry will be kept only if it is listed in the opened file. To  | ||||||
|  | " remove old header entry despite of the setting just remove it from the  | ||||||
|  | " listing. Setting it to false makes plugin ignore all header entries. Defaults  | ||||||
|  | " to 1. | ||||||
|  | let g:shada#keep_old_header = get(g:, 'shada#keep_old_header', 1) | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " If true then first entry will be plugin’s own header entry. | ||||||
|  | let g:shada#add_own_header = get(g:, 'shada#add_own_header', 1) | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dictionary that maps ShaDa types to their names. | ||||||
|  | let s:SHADA_ENTRY_NAMES = { | ||||||
|  |   \1: 'header', | ||||||
|  |   \2: 'search_pattern', | ||||||
|  |   \3: 'replacement_string', | ||||||
|  |   \4: 'history_entry', | ||||||
|  |   \5: 'register', | ||||||
|  |   \6: 'variable', | ||||||
|  |   \7: 'global_mark', | ||||||
|  |   \8: 'jump', | ||||||
|  |   \9: 'buffer_list', | ||||||
|  |   \10: 'local_mark', | ||||||
|  |   \11: 'change', | ||||||
|  | \} | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dictionary that maps ShaDa names to corresponding types | ||||||
|  | let s:SHADA_ENTRY_TYPES = {} | ||||||
|  | call map(copy(s:SHADA_ENTRY_NAMES), | ||||||
|  |         \'extend(s:SHADA_ENTRY_TYPES, {v:val : +v:key})') | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Map that maps entry names to lists of keys that can be used by this entry.  | ||||||
|  | " Only contains data for entries which are represented as mappings, except for  | ||||||
|  | " the header. | ||||||
|  | let s:SHADA_MAP_ENTRIES = { | ||||||
|  |   \'search_pattern': ['sp', 'sh', 'ss', 'sm', 'sc', 'sl', 'se', 'so', 'su'], | ||||||
|  |   \'register': ['n', 'rc', 'rw', 'rt'], | ||||||
|  |   \'global_mark': ['n', 'f', 'l', 'c'], | ||||||
|  |   \'local_mark': ['f', 'n', 'l', 'c'], | ||||||
|  |   \'jump': ['f', 'l', 'c'], | ||||||
|  |   \'change': ['f', 'l', 'c'], | ||||||
|  |   \'header': [], | ||||||
|  | \} | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Like one of the values from s:SHADA_MAP_ENTRIES, but for a single buffer in  | ||||||
|  | " buffer list entry. | ||||||
|  | let s:SHADA_BUFFER_LIST_KEYS = ['f', 'l', 'c'] | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " List of possible history types. Maps integer values that represent history  | ||||||
|  | " types to human-readable names. | ||||||
|  | let s:SHADA_HISTORY_TYPES = ['command', 'search', 'expression', 'input', 'debug'] | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Map that maps entry names to their descriptions. Only for entries which have  | ||||||
|  | " list as a data type. Description is a list of lists where each entry has item  | ||||||
|  | " description and item type. | ||||||
|  | let s:SHADA_FIXED_ARRAY_ENTRIES = { | ||||||
|  |   \'replacement_string': [[':s replacement string', 'bin']], | ||||||
|  |   \'history_entry': [ | ||||||
|  |     \['history type', 'histtype'], | ||||||
|  |     \['contents', 'bin'], | ||||||
|  |     \['separator', 'intchar'], | ||||||
|  |   \], | ||||||
|  |   \'variable': [['name', 'bin'], ['value', 'any']], | ||||||
|  | \} | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dictionary that maps enum names to dictionary with enum values. Dictionary  | ||||||
|  | " with enum values maps enum human-readable names to corresponding values. Enums  | ||||||
|  | " are used as type names in s:SHADA_FIXED_ARRAY_ENTRIES and  | ||||||
|  | " s:SHADA_STANDARD_KEYS. | ||||||
|  | let s:SHADA_ENUMS = { | ||||||
|  |   \'histtype': { | ||||||
|  |     \'CMD': 0, | ||||||
|  |     \'SEARCH': 1, | ||||||
|  |     \'EXPR': 2, | ||||||
|  |     \'INPUT': 3, | ||||||
|  |     \'DEBUG': 4, | ||||||
|  |   \}, | ||||||
|  |   \'regtype': { | ||||||
|  |     \'CHARACTERWISE': 0, | ||||||
|  |     \'LINEWISE': 1, | ||||||
|  |     \'BLOCKWISE': 2, | ||||||
|  |   \} | ||||||
|  | \} | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Second argument to msgpack#eval. | ||||||
|  | let s:SHADA_SPECIAL_OBJS = {} | ||||||
|  | call map(values(s:SHADA_ENUMS), | ||||||
|  |         \'extend(s:SHADA_SPECIAL_OBJS, map(copy(v:val), "string(v:val)"))') | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Like s:SHADA_ENUMS, but inner dictionary maps values to names and not names to  | ||||||
|  | " values. | ||||||
|  | let s:SHADA_REV_ENUMS = map(copy(s:SHADA_ENUMS), '{}') | ||||||
|  | call map(copy(s:SHADA_ENUMS), | ||||||
|  |         \'map(copy(v:val), ' | ||||||
|  |           \. '"extend(s:SHADA_REV_ENUMS[" . string(v:key) . "], ' | ||||||
|  |                   \. '{v:val : v:key})")') | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Maximum length of ShaDa entry name. Used to arrange entries to the table. | ||||||
|  | let s:SHADA_MAX_ENTRY_LENGTH = max( | ||||||
|  |       \map(values(s:SHADA_ENTRY_NAMES), 'len(v:val)') | ||||||
|  |       \+ [len('unknown (0x)') + 16]) | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Object that marks required value. | ||||||
|  | let s:SHADA_REQUIRED = [] | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Dictionary that maps default key names to their description. Description is  | ||||||
|  | " a list that contains human-readable hint, key type and default value. | ||||||
|  | let s:SHADA_STANDARD_KEYS = { | ||||||
|  |   \'sm': ['magic value', 'boolean', g:msgpack#true], | ||||||
|  |   \'sc': ['smartcase value', 'boolean', g:msgpack#false], | ||||||
|  |   \'sl': ['has line offset', 'boolean', g:msgpack#false], | ||||||
|  |   \'se': ['place cursor at end', 'boolean', g:msgpack#false], | ||||||
|  |   \'so': ['offset value', 'integer', 0], | ||||||
|  |   \'su': ['is last used', 'boolean', g:msgpack#true], | ||||||
|  |   \'ss': ['is :s pattern', 'boolean', g:msgpack#false], | ||||||
|  |   \'sh': ['v:hlsearch value', 'boolean', g:msgpack#false], | ||||||
|  |   \'sp': ['pattern', 'bin', s:SHADA_REQUIRED], | ||||||
|  |   \'rt': ['type', 'regtype', s:SHADA_ENUMS.regtype.CHARACTERWISE], | ||||||
|  |   \'rw': ['block width', 'uint', 0], | ||||||
|  |   \'rc': ['contents', 'binarray', s:SHADA_REQUIRED], | ||||||
|  |   \'n':  ['name', 'intchar', char2nr('"')], | ||||||
|  |   \'l':  ['line number', 'uint', 1], | ||||||
|  |   \'c':  ['column', 'uint', 0], | ||||||
|  |   \'f':  ['file name', 'bin', s:SHADA_REQUIRED], | ||||||
|  | \} | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Set of entry types containing entries which require `n` key. | ||||||
|  | let s:SHADA_REQUIRES_NAME = {'local_mark': 1, 'global_mark': 1, 'register': 1} | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Maximum width of human-readable hint. Used to arrange data in table. | ||||||
|  | let s:SHADA_MAX_HINT_WIDTH = max(map(values(s:SHADA_STANDARD_KEYS), | ||||||
|  |                                     \'len(v:val[0])')) | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Default mark name for the cases when it makes sense (i.e. for local marks). | ||||||
|  | let s:SHADA_DEFAULT_MARK_NAME = '"' | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Mapping that maps timestamps represented using msgpack#string to strftime  | ||||||
|  | " output. Used by s:shada_strftime. | ||||||
|  | let s:shada_strftime_cache = {} | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Mapping that maps strftime output from s:shada_strftime to timestamps. | ||||||
|  | let s:shada_strptime_cache = {} | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Time format used for displaying ShaDa files. | ||||||
|  | let s:SHADA_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S' | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Wrapper around msgpack#strftime that caches its output. | ||||||
|  | " | ||||||
|  | " Format is hardcoded to s:SHADA_TIME_FORMAT. | ||||||
|  | function s:shada_strftime(timestamp) abort | ||||||
|  |   let key = msgpack#string(a:timestamp) | ||||||
|  |   if has_key(s:shada_strftime_cache, key) | ||||||
|  |     return s:shada_strftime_cache[key] | ||||||
|  |   endif | ||||||
|  |   let val = msgpack#strftime(s:SHADA_TIME_FORMAT, a:timestamp) | ||||||
|  |   let s:shada_strftime_cache[key] = val | ||||||
|  |   let s:shada_strptime_cache[val] = a:timestamp | ||||||
|  |   return val | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Wrapper around msgpack#strftime that uses cache created by s:shada_strftime(). | ||||||
|  | " | ||||||
|  | " Also caches its own results. Format is hardcoded to s:SHADA_TIME_FORMAT. | ||||||
|  | function s:shada_strptime(string) abort | ||||||
|  |   if has_key(s:shada_strptime_cache, a:string) | ||||||
|  |     return s:shada_strptime_cache[a:string] | ||||||
|  |   endif | ||||||
|  |   let ts = msgpack#strptime(s:SHADA_TIME_FORMAT, a:string) | ||||||
|  |   let s:shada_strptime_cache[a:string] = ts | ||||||
|  |   return ts | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Check whether given value matches given type. | ||||||
|  | " | ||||||
|  | " @return Zero if value matches, error message string if it does not. | ||||||
|  | function s:shada_check_type(type, val) abort | ||||||
|  |   let type = msgpack#type(a:val) | ||||||
|  |   if type is# a:type | ||||||
|  |     return 0 | ||||||
|  |   endif | ||||||
|  |   if has_key(s:SHADA_ENUMS, a:type) | ||||||
|  |     let msg = s:shada_check_type('uint', a:val) | ||||||
|  |     if msg isnot 0 | ||||||
|  |       return msg | ||||||
|  |     endif | ||||||
|  |     if !has_key(s:SHADA_REV_ENUMS[a:type], a:val) | ||||||
|  |       let evals_msg = join(map(sort(items(s:SHADA_REV_ENUMS[a:type])), | ||||||
|  |                               \'v:val[0] . " (" . v:val[1] . ")"'), ', ') | ||||||
|  |       return 'Unexpected enum value: expected one of ' . evals_msg | ||||||
|  |     endif | ||||||
|  |     return 0 | ||||||
|  |   elseif a:type is# 'uint' | ||||||
|  |     if type isnot# 'integer' | ||||||
|  |       return 'Expected integer' | ||||||
|  |     endif | ||||||
|  |     if !(type(a:val) == type({}) ? a:val._VAL[0] == 1 : a:val >= 0) | ||||||
|  |       return 'Value is negative' | ||||||
|  |     endif | ||||||
|  |     return 0 | ||||||
|  |   elseif a:type is# 'bin' | ||||||
|  |     " Binary string without zero bytes | ||||||
|  |     if type isnot# 'binary' | ||||||
|  |       return 'Expected binary string' | ||||||
|  |     elseif (type(a:val) == type({}) | ||||||
|  |            \&& !empty(filter(copy(a:val._VAL), 'stridx(v:val, "\n") != -1'))) | ||||||
|  |       return 'Expected no NUL bytes' | ||||||
|  |     endif | ||||||
|  |     return 0 | ||||||
|  |   elseif a:type is# 'intchar' | ||||||
|  |     let msg = s:shada_check_type('uint', a:val) | ||||||
|  |     if msg isnot# 0 | ||||||
|  |       return msg | ||||||
|  |     endif | ||||||
|  |     if a:val > 0 || a:val < 1 | ||||||
|  |     endif | ||||||
|  |     return 0 | ||||||
|  |   elseif a:type is# 'binarray' | ||||||
|  |     if type isnot# 'array' | ||||||
|  |       return 'Expected array value' | ||||||
|  |     elseif !empty(filter(copy(type(a:val) == type({}) ? a:val._VAL : a:val), | ||||||
|  |                         \'msgpack#type(v:val) isnot# "binary"')) | ||||||
|  |       return 'Expected array of binary strings' | ||||||
|  |     else | ||||||
|  |       for element in (type(a:val) == type({}) ? a:val._VAL : a:val) | ||||||
|  |         if (type(element) == type({}) | ||||||
|  |            \&& !empty(filter(copy(element._VAL), 'stridx(v:val, "\n") != -1'))) | ||||||
|  |           return 'Expected no NUL bytes' | ||||||
|  |         endif | ||||||
|  |         unlet element | ||||||
|  |       endfor | ||||||
|  |     endif | ||||||
|  |     return 0 | ||||||
|  |   elseif a:type is# 'boolean' | ||||||
|  |     return 'Expected boolean' | ||||||
|  |   elseif a:type is# 'integer' | ||||||
|  |     return 'Expected integer' | ||||||
|  |   elseif a:type is# 'any' | ||||||
|  |     return 0 | ||||||
|  |   endif | ||||||
|  |   return 'Internal error: unknown type ' . a:type | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert msgpack mapping object to a list of strings for  | ||||||
|  | " s:shada_convert_entry(). | ||||||
|  | " | ||||||
|  | " @param[in]  map           Mapping to convert. | ||||||
|  | " @param[in]  default_keys  List of keys which have default value in this  | ||||||
|  | "                           mapping. | ||||||
|  | " @param[in]  name          Name of the converted entry. | ||||||
|  | function s:shada_convert_map(map, default_keys, name) abort | ||||||
|  |   let ret = [] | ||||||
|  |   let keys = copy(a:default_keys) | ||||||
|  |   call map(sort(keys(a:map)), 'index(keys, v:val) == -1 ? add(keys, v:val) : 0') | ||||||
|  |   let descriptions = map(copy(keys), | ||||||
|  |                         \'get(s:SHADA_STANDARD_KEYS, v:val, ["", 0, 0])') | ||||||
|  |   let max_key_len = max(map(copy(keys), 'len(v:val)')) | ||||||
|  |   let max_desc_len = max(map(copy(descriptions), | ||||||
|  |                             \'v:val[0] is 0 ? 0 : len(v:val[0])')) | ||||||
|  |   if max_key_len < len('Key') | ||||||
|  |     let max_key_len = len('Key') | ||||||
|  |   endif | ||||||
|  |   let key_header = 'Key' . repeat('_', max_key_len - len('Key')) | ||||||
|  |   if max_desc_len == 0 | ||||||
|  |     call add(ret, printf('  %% %s  %s', key_header, 'Value')) | ||||||
|  |   else | ||||||
|  |     if max_desc_len < len('Description') | ||||||
|  |       let max_desc_len = len('Description') | ||||||
|  |     endif | ||||||
|  |     let desc_header = ('Description' | ||||||
|  |                       \. repeat('_', max_desc_len - len('Description'))) | ||||||
|  |     call add(ret, printf('  %% %s  %s  %s', key_header, desc_header, 'Value')) | ||||||
|  |   endif | ||||||
|  |   let i = 0 | ||||||
|  |   for key in keys | ||||||
|  |     let [description, type, default] = descriptions[i] | ||||||
|  |     if a:name isnot# 'local_mark' && key is# 'n' | ||||||
|  |       unlet default | ||||||
|  |       let default = s:SHADA_REQUIRED | ||||||
|  |     endif | ||||||
|  |     let value = get(a:map, key, default) | ||||||
|  |     if (key is# 'n' && !has_key(s:SHADA_REQUIRES_NAME, a:name) | ||||||
|  |        \&& value is# s:SHADA_REQUIRED) | ||||||
|  |       " Do nothing | ||||||
|  |     elseif value is s:SHADA_REQUIRED | ||||||
|  |       call add(ret, '  # Required key missing: ' . key) | ||||||
|  |     elseif max_desc_len == 0 | ||||||
|  |       call add(ret, printf('  + %-*s  %s', | ||||||
|  |                           \max_key_len, key, | ||||||
|  |                           \msgpack#string(value))) | ||||||
|  |     else | ||||||
|  |       if type isnot 0 && value isnot# default | ||||||
|  |         let msg = s:shada_check_type(type, value) | ||||||
|  |         if msg isnot 0 | ||||||
|  |           call add(ret, '  # ' . msg) | ||||||
|  |         endif | ||||||
|  |       endif | ||||||
|  |       let strval = s:shada_string(type, value) | ||||||
|  |       if msgpack#type(value) is# 'array' && msg is 0 | ||||||
|  |         let shift = 2 + 2 + max_key_len + 2 + max_desc_len + 2 | ||||||
|  |         " Value:    1   2   3             4   5              6: | ||||||
|  |         " "  + Key  Description  Value" | ||||||
|  |         "  1122333445555555555566 | ||||||
|  |         if shift + strdisplaywidth(strval, shift) > 80 | ||||||
|  |           let strval = '@' | ||||||
|  |         endif | ||||||
|  |       endif | ||||||
|  |       call add(ret, printf('  + %-*s  %-*s  %s', | ||||||
|  |                           \max_key_len, key, | ||||||
|  |                           \max_desc_len, description, | ||||||
|  |                           \strval)) | ||||||
|  |       if strval is '@' | ||||||
|  |         for v in value | ||||||
|  |           call add(ret, printf('  | - %s', msgpack#string(v))) | ||||||
|  |           unlet v | ||||||
|  |         endfor | ||||||
|  |       endif | ||||||
|  |     endif | ||||||
|  |     let i += 1 | ||||||
|  |     unlet value | ||||||
|  |     unlet default | ||||||
|  |   endfor | ||||||
|  |   return ret | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Wrapper around msgpack#string() which may return string from s:SHADA_REV_ENUMS | ||||||
|  | function s:shada_string(type, v) abort | ||||||
|  |   if (has_key(s:SHADA_ENUMS, a:type) && type(a:v) == type(0) | ||||||
|  |      \&& has_key(s:SHADA_REV_ENUMS[a:type], a:v)) | ||||||
|  |     return s:SHADA_REV_ENUMS[a:type][a:v] | ||||||
|  |   elseif (a:type is# 'intchar' && type(a:v) == type(0) | ||||||
|  |          \&& strtrans(nr2char(a:v)) is# nr2char(a:v)) | ||||||
|  |     return "'" . nr2char(a:v) . "'" | ||||||
|  |   else | ||||||
|  |     return msgpack#string(a:v) | ||||||
|  |   endif | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Evaluate string obtained by s:shada_string(). | ||||||
|  | function s:shada_eval(s) abort | ||||||
|  |   return msgpack#eval(a:s, s:SHADA_SPECIAL_OBJS) | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert one ShaDa entry to a list of strings suitable for setline(). | ||||||
|  | " | ||||||
|  | " Returned format looks like this: | ||||||
|  | " | ||||||
|  | "     TODO | ||||||
|  | function s:shada_convert_entry(entry) abort | ||||||
|  |   if type(a:entry.type) == type({}) | ||||||
|  |     " |msgpack-special-dict| may only be used if value does not fit into the  | ||||||
|  |     " default integer type. All known entry types do fit, so it is definitely  | ||||||
|  |     " unknown entry. | ||||||
|  |     let name = 'unknown_(' . msgpack#int_dict_to_str(a:entry.type) . ')' | ||||||
|  |   else | ||||||
|  |     let name = get(s:SHADA_ENTRY_NAMES, a:entry.type, 0) | ||||||
|  |     if name is 0 | ||||||
|  |       let name = printf('unknown_(0x%x)', a:entry.type) | ||||||
|  |     endif | ||||||
|  |   endif | ||||||
|  |   let title = toupper(name[0]) . tr(name[1:], '_', ' ') | ||||||
|  |   let header = printf('%s with timestamp %s:', title, | ||||||
|  |                      \s:shada_strftime(a:entry.timestamp)) | ||||||
|  |   let ret = [header] | ||||||
|  |   if name[:8] is# 'unknown_(' && name[-1:] is# ')' | ||||||
|  |     call add(ret, '  = ' . msgpack#string(a:entry.data)) | ||||||
|  |   elseif has_key(s:SHADA_FIXED_ARRAY_ENTRIES, name) | ||||||
|  |     if type(a:entry.data) != type([]) | ||||||
|  |       call add(ret, printf('  # Unexpected type: %s instead of array', | ||||||
|  |                           \msgpack#type(a:entry.data))) | ||||||
|  |       call add(ret, '  = ' . msgpack#string(a:entry.data)) | ||||||
|  |       return ret | ||||||
|  |     endif | ||||||
|  |     let i = 0 | ||||||
|  |     let max_desc_len = max(map(copy(s:SHADA_FIXED_ARRAY_ENTRIES[name]), | ||||||
|  |                               \'len(v:val[0])')) | ||||||
|  |     if max_desc_len < len('Description') | ||||||
|  |       let max_desc_len = len('Description') | ||||||
|  |     endif | ||||||
|  |     let desc_header = ('Description' | ||||||
|  |                       \. repeat('_', max_desc_len - len('Description'))) | ||||||
|  |     call add(ret, printf('  @ %s  %s', desc_header, 'Value')) | ||||||
|  |     for value in a:entry.data | ||||||
|  |       let [desc, type] = get(s:SHADA_FIXED_ARRAY_ENTRIES[name], i, ['', 0]) | ||||||
|  |       if (i == 2 && name is# 'history_entry' | ||||||
|  |          \&& a:entry.data[0] isnot# s:SHADA_ENUMS.histtype.SEARCH) | ||||||
|  |         let [desc, type] = ['', 0] | ||||||
|  |       endif | ||||||
|  |       if type isnot 0 | ||||||
|  |         let msg = s:shada_check_type(type, value) | ||||||
|  |         if msg isnot 0 | ||||||
|  |           call add(ret, '  # ' . msg) | ||||||
|  |         endif | ||||||
|  |       endif | ||||||
|  |       call add(ret, printf('  - %-*s  %s', max_desc_len, desc, | ||||||
|  |                           \s:shada_string(type, value))) | ||||||
|  |       let i += 1 | ||||||
|  |       unlet value | ||||||
|  |     endfor | ||||||
|  |     if (len(a:entry.data) < len(s:SHADA_FIXED_ARRAY_ENTRIES[name]) | ||||||
|  |        \&& !(name is# 'history_entry' | ||||||
|  |             \&& len(a:entry.data) == 2 | ||||||
|  |             \&& a:entry.data[0] isnot# s:SHADA_ENUMS.histtype.SEARCH)) | ||||||
|  |       call add(ret, '  # Expected more elements in list') | ||||||
|  |     endif | ||||||
|  |   elseif has_key(s:SHADA_MAP_ENTRIES, name) | ||||||
|  |     if type(a:entry.data) != type({}) | ||||||
|  |       call add(ret, printf('  # Unexpected type: %s instead of map', | ||||||
|  |                           \msgpack#type(a:entry.data))) | ||||||
|  |       call add(ret, '  = ' . msgpack#string(a:entry.data)) | ||||||
|  |       return ret | ||||||
|  |     endif | ||||||
|  |     if msgpack#special_type(a:entry.data) isnot 0 | ||||||
|  |       call add(ret, '  # Entry is a special dict which is unexpected') | ||||||
|  |       call add(ret, '  = ' . msgpack#string(a:entry.data)) | ||||||
|  |       return ret | ||||||
|  |     endif | ||||||
|  |     let ret += s:shada_convert_map(a:entry.data, s:SHADA_MAP_ENTRIES[name], | ||||||
|  |                                   \name) | ||||||
|  |   elseif name is# 'buffer_list' | ||||||
|  |     if type(a:entry.data) != type([]) | ||||||
|  |       call add(ret, printf('  # Unexpected type: %s instead of array', | ||||||
|  |                           \msgpack#type(a:entry.data))) | ||||||
|  |       call add(ret, '  = ' . msgpack#string(a:entry.data)) | ||||||
|  |       return ret | ||||||
|  |     elseif !empty(filter(copy(a:entry.data), | ||||||
|  |                         \'type(v:val) != type({}) ' | ||||||
|  |                       \. '|| msgpack#special_type(v:val) isnot 0')) | ||||||
|  |       call add(ret, '  # Expected array of maps') | ||||||
|  |       call add(ret, '  = ' . msgpack#string(a:entry.data)) | ||||||
|  |       return ret | ||||||
|  |     endif | ||||||
|  |     for bufdef in a:entry.data | ||||||
|  |       if bufdef isnot a:entry.data[0] | ||||||
|  |         call add(ret, '') | ||||||
|  |       endif | ||||||
|  |       let ret += s:shada_convert_map(bufdef, s:SHADA_BUFFER_LIST_KEYS, name) | ||||||
|  |     endfor | ||||||
|  |   else | ||||||
|  |     throw 'internal-unknown-type:Internal error: unknown type name: ' . name | ||||||
|  |   endif | ||||||
|  |   return ret | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Order of msgpack objects in one ShaDa entry. Each item in the list is name of  | ||||||
|  | " the key in dictionaries returned by shada#read(). | ||||||
|  | let s:SHADA_ENTRY_OBJECT_SEQUENCE = ['type', 'timestamp', 'length', 'data'] | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert list returned by msgpackparse() to a list of ShaDa objects | ||||||
|  | " | ||||||
|  | " @param[in]  mpack  List of VimL objects returned by msgpackparse(). | ||||||
|  | " | ||||||
|  | " @return List of dictionaries with keys type, timestamp, length and data. Each  | ||||||
|  | "         dictionary describes one ShaDa entry. | ||||||
|  | function shada#mpack_to_sd(mpack) abort | ||||||
|  |   let ret = [] | ||||||
|  |   let i = 0 | ||||||
|  |   for element in a:mpack | ||||||
|  |     let key = s:SHADA_ENTRY_OBJECT_SEQUENCE[ | ||||||
|  |           \i % len(s:SHADA_ENTRY_OBJECT_SEQUENCE)] | ||||||
|  |     if key is# 'type' | ||||||
|  |       call add(ret, {}) | ||||||
|  |     endif | ||||||
|  |     let ret[-1][key] = element | ||||||
|  |     if key isnot# 'data' | ||||||
|  |       if !msgpack#is_uint(element) | ||||||
|  |         throw printf('not-uint:Entry %i has %s element '. | ||||||
|  |                     \'which is not an unsigned integer', | ||||||
|  |                     \len(ret), key) | ||||||
|  |       endif | ||||||
|  |       if key is# 'type' && msgpack#equal(element, 0) | ||||||
|  |         throw printf('zero-uint:Entry %i has %s element '. | ||||||
|  |                     \'which is zero', | ||||||
|  |                     \len(ret), key) | ||||||
|  |       endif | ||||||
|  |     endif | ||||||
|  |     let i += 1 | ||||||
|  |     unlet element | ||||||
|  |   endfor | ||||||
|  |   return ret | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert read ShaDa file to a list of lines suitable for setline() | ||||||
|  | " | ||||||
|  | " @param[in]  shada  List of ShaDa entries like returned by shada#mpack_to_sd(). | ||||||
|  | " | ||||||
|  | " @return List of strings suitable for setline()-like functions. | ||||||
|  | function shada#sd_to_strings(shada) abort | ||||||
|  |   let ret = [] | ||||||
|  |   for entry in a:shada | ||||||
|  |     let ret += s:shada_convert_entry(entry) | ||||||
|  |   endfor | ||||||
|  |   return ret | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert a readfile()-like list of strings to a list of lines suitable for  | ||||||
|  | " setline(). | ||||||
|  | " | ||||||
|  | " @param[in]  binstrings  List of strings to convert. | ||||||
|  | " | ||||||
|  | " @return List of lines. | ||||||
|  | function shada#get_strings(binstrings) abort | ||||||
|  |   return shada#sd_to_strings(shada#mpack_to_sd(msgpackparse(a:binstrings))) | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert s:shada_convert_entry() output to original entry. | ||||||
|  | function s:shada_convert_strings(strings) abort | ||||||
|  |   let strings = copy(a:strings) | ||||||
|  |   let match = matchlist( | ||||||
|  |         \strings[0], | ||||||
|  |         \'\v\C^(.{-})\m with timestamp \(\d\{4}-\d\d-\d\dT\d\d:\d\d:\d\d\):$') | ||||||
|  |   if empty(match) | ||||||
|  |     throw 'invalid-header:Header has invalid format: ' . strings[0] | ||||||
|  |   endif | ||||||
|  |   call remove(strings, 0) | ||||||
|  |   let title = match[1] | ||||||
|  |   let name = tolower(title[0]) . tr(title[1:], ' ', '_') | ||||||
|  |   let ret = {} | ||||||
|  |   let empty_default = g:msgpack#nil | ||||||
|  |   if name[:8] is# 'unknown_(' && name[-1:] is# ')' | ||||||
|  |     let ret.type = +name[9:-2] | ||||||
|  |   elseif has_key(s:SHADA_ENTRY_TYPES, name) | ||||||
|  |     let ret.type = s:SHADA_ENTRY_TYPES[name] | ||||||
|  |     if has_key(s:SHADA_MAP_ENTRIES, name) | ||||||
|  |       unlet empty_default | ||||||
|  |       let empty_default = {} | ||||||
|  |     elseif has_key(s:SHADA_FIXED_ARRAY_ENTRIES, name) || name is# 'buffer_list' | ||||||
|  |       unlet empty_default | ||||||
|  |       let empty_default = [] | ||||||
|  |     endif | ||||||
|  |   else | ||||||
|  |     throw 'invalid-type:Unknown type ' . name | ||||||
|  |   endif | ||||||
|  |   let ret.timestamp = s:shada_strptime(match[2]) | ||||||
|  |   if empty(strings) | ||||||
|  |     let ret.data = empty_default | ||||||
|  |   else | ||||||
|  |     while !empty(strings) | ||||||
|  |       if strings[0][2] is# '=' | ||||||
|  |         let data = s:shada_eval(strings[0][4:]) | ||||||
|  |         call remove(strings, 0) | ||||||
|  |       elseif strings[0][2] is# '%' | ||||||
|  |         if name is# 'buffer_list' && !has_key(ret, 'data') | ||||||
|  |           let ret.data = [] | ||||||
|  |         endif | ||||||
|  |         let match = matchlist( | ||||||
|  |               \strings[0], | ||||||
|  |               \'\m\C^  % \(Key_*\)\(  Description_*\)\?  Value') | ||||||
|  |         if empty(match) | ||||||
|  |           throw 'invalid-map-header:Invalid mapping header: ' . strings[0] | ||||||
|  |         endif | ||||||
|  |         call remove(strings, 0) | ||||||
|  |         let key_len = len(match[1]) | ||||||
|  |         let desc_skip_len = len(match[2]) | ||||||
|  |         let data = {'_TYPE': v:msgpack_types.map, '_VAL': []} | ||||||
|  |         while !empty(strings) && strings[0][2] is# '+' | ||||||
|  |           let line = remove(strings, 0)[4:] | ||||||
|  |           let key = substitute(line[:key_len - 1], '\v\C\ *$', '', '') | ||||||
|  |           let strval = line[key_len + desc_skip_len + 2:] | ||||||
|  |           if strval is# '@' | ||||||
|  |             let val = [] | ||||||
|  |             while !empty(strings) && strings[0][2] is# '|' | ||||||
|  |               if strings[0][4] isnot# '-' | ||||||
|  |                 throw ('invalid-array:Expected hyphen-minus at column 5: ' | ||||||
|  |                       \. strings) | ||||||
|  |               endif | ||||||
|  |               call add(val, s:shada_eval(remove(strings, 0)[5:])) | ||||||
|  |             endwhile | ||||||
|  |           else | ||||||
|  |             let val = s:shada_eval(strval) | ||||||
|  |           endif | ||||||
|  |           if (has_key(s:SHADA_STANDARD_KEYS, key) | ||||||
|  |              \&& s:SHADA_STANDARD_KEYS[key][2] isnot# s:SHADA_REQUIRED | ||||||
|  |              \&& msgpack#equal(s:SHADA_STANDARD_KEYS[key][2], val)) | ||||||
|  |             unlet val | ||||||
|  |             continue | ||||||
|  |           endif | ||||||
|  |           call add(data._VAL, [{'_TYPE': v:msgpack_types.string, '_VAL': [key]}, | ||||||
|  |                               \val]) | ||||||
|  |           unlet val | ||||||
|  |         endwhile | ||||||
|  |       elseif strings[0][2] is# '@' | ||||||
|  |         let match = matchlist( | ||||||
|  |               \strings[0], | ||||||
|  |               \'\m\C^  @ \(Description_*  \)\?Value') | ||||||
|  |         if empty(match) | ||||||
|  |           throw 'invalid-array-header:Invalid array header: ' . strings[0] | ||||||
|  |         endif | ||||||
|  |         call remove(strings, 0) | ||||||
|  |         let desc_skip_len = len(match[1]) | ||||||
|  |         let data = [] | ||||||
|  |         while !empty(strings) && strings[0][2] is# '-' | ||||||
|  |           let val = remove(strings, 0)[4 + desc_skip_len :] | ||||||
|  |           call add(data, s:shada_eval(val)) | ||||||
|  |         endwhile | ||||||
|  |       else | ||||||
|  |         throw 'invalid-line:Unrecognized line: ' . strings[0] | ||||||
|  |       endif | ||||||
|  |       if !has_key(ret, 'data') | ||||||
|  |         let ret.data = data | ||||||
|  |       elseif type(ret.data) == type([]) | ||||||
|  |         call add(ret.data, data) | ||||||
|  |       else | ||||||
|  |         let ret.data = [ret.data, data] | ||||||
|  |       endif | ||||||
|  |       unlet data | ||||||
|  |     endwhile | ||||||
|  |   endif | ||||||
|  |   let ret._data = msgpackdump([ret.data]) | ||||||
|  |   let ret.length = len(ret._data) - 1 | ||||||
|  |   for s in ret._data | ||||||
|  |     let ret.length += len(s) | ||||||
|  |   endfor | ||||||
|  |   return ret | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert s:shada_sd_to_strings() output to a list of original entries. | ||||||
|  | function shada#strings_to_sd(strings) abort | ||||||
|  |   let strings = filter(copy(a:strings), 'v:val !~# ''\v^\s*%(\#|$)''') | ||||||
|  |   let stringss = [] | ||||||
|  |   for string in strings | ||||||
|  |     if string[0] isnot# ' ' | ||||||
|  |       call add(stringss, []) | ||||||
|  |     endif | ||||||
|  |     call add(stringss[-1], string) | ||||||
|  |   endfor | ||||||
|  |   return map(copy(stringss), 's:shada_convert_strings(v:val)') | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | "" | ||||||
|  | " Convert a list of strings to list of strings suitable for writefile(). | ||||||
|  | function shada#get_binstrings(strings) abort | ||||||
|  |   let entries = shada#strings_to_sd(a:strings) | ||||||
|  |   if !g:shada#keep_old_header | ||||||
|  |     call filter(entries, 'v:val.type != ' . s:SHADA_ENTRY_TYPES.header) | ||||||
|  |   endif | ||||||
|  |   if g:shada#add_own_header | ||||||
|  |     let data = {'version': v:version, 'generator': 'shada.vim'} | ||||||
|  |     let dumped_data = msgpackdump([data]) | ||||||
|  |     let length = len(dumped_data) - 1 | ||||||
|  |     for s in dumped_data | ||||||
|  |       let length += len(s) | ||||||
|  |     endfor | ||||||
|  |     call insert(entries, { | ||||||
|  |             \'type': s:SHADA_ENTRY_TYPES.header, | ||||||
|  |             \'timestamp': localtime(), | ||||||
|  |             \'length': length, | ||||||
|  |             \'data': data, | ||||||
|  |             \'_data': dumped_data, | ||||||
|  |           \}) | ||||||
|  |   endif | ||||||
|  |   let mpack = [] | ||||||
|  |   for entry in entries | ||||||
|  |     let mpack += map(copy(s:SHADA_ENTRY_OBJECT_SEQUENCE), 'entry[v:val]') | ||||||
|  |   endfor | ||||||
|  |   return msgpackdump(mpack) | ||||||
|  | endfunction | ||||||
| @@ -557,6 +557,149 @@ Since the text for this plugin is rather long it has been put in a separate | |||||||
| file: |pi_spec.txt|. | file: |pi_spec.txt|. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SHADA							*ft-shada* | ||||||
|  |  | ||||||
|  | Allows editing binary |shada-file|s in a nice way.  Opened binary files are  | ||||||
|  | displayed in the following format: > | ||||||
|  |  | ||||||
|  |     Type with timestamp YYYY-mm-ddTHH:MM:SS: | ||||||
|  |       % Key__  Description___  Value | ||||||
|  |       + fooba  foo bar baz fo  {msgpack-value} | ||||||
|  |       + abcde  abc def ghi jk  {msgpack-value} | ||||||
|  |     Other type with timestamp YYYY-mm-ddTHH:MM:SS: | ||||||
|  |       @ Description__  Value | ||||||
|  |       - foo bar baz t  {msgpack-value} | ||||||
|  |       # Expected more elements in list | ||||||
|  |     Some other type with timestamp YYYY-mm-ddTHH:MM:SS: | ||||||
|  |       # Unexpected type: type instead of map | ||||||
|  |       = {msgpack-value} | ||||||
|  |  | ||||||
|  | Filetype plugin defines all |Cmd-event|s.  Defined |SourceCmd| event makes  | ||||||
|  | "source file.shada" be equivalent to "|:rshada| file.shada".  |BufWriteCmd|,  | ||||||
|  | |FileWriteCmd| and |FileAppendCmd| events are affected by the following  | ||||||
|  | settings: | ||||||
|  |  | ||||||
|  | *g:shada#keep_old_header*	Boolean, if set to false all header entries  | ||||||
|  | 				are ignored when writing.  Defaults to 1. | ||||||
|  | *g:shada#add_own_header*	Boolean, if set to true first written entry  | ||||||
|  | 				will always be header entry with two values in  | ||||||
|  | 				a map with attached data: |v:version| attached  | ||||||
|  | 				to "version" key and "shada.vim" attached to  | ||||||
|  | 				"generator" key.  Defaults to 1. | ||||||
|  |  | ||||||
|  | Format description: | ||||||
|  |  | ||||||
|  | 1. `#` starts a comment.  Lines starting with space characters and then `#`  | ||||||
|  |    are ignored.  Plugin may only add comment lines to indicate some errors in  | ||||||
|  |    ShaDa format.  Lines containing no non-whitespace characters are also  | ||||||
|  |    ignored. | ||||||
|  | 2. Each entry starts with line that has format "{type} with timestamp  | ||||||
|  |    {timestamp}:". {timestamp} is |strftime()|-formatted string representing  | ||||||
|  |    actual UNIX timestamp value. First strftime() argument is equal to  | ||||||
|  |    `%Y-%m-%dT%H:%M:%S`.  When writing this timestamp is parsed using  | ||||||
|  |    |msgpack#strptime()|, with caching (it remembers which timestamp produced  | ||||||
|  |    particular strftime() output and uses this value if you did not change  | ||||||
|  |    timestamp). {type} is one of | ||||||
|  |     1 - Header | ||||||
|  |     2 - Search pattern | ||||||
|  |     3 - Replacement string | ||||||
|  |     4 - History entry | ||||||
|  |     5 - Register | ||||||
|  |     6 - Variable | ||||||
|  |     7 - Global mark | ||||||
|  |     8 - Jump | ||||||
|  |     9 - Buffer list | ||||||
|  |    10 - Local mark | ||||||
|  |    11 - Change | ||||||
|  |     * - Unknown (0x{type-hex}) | ||||||
|  |  | ||||||
|  |    Each type may be represented using Unknown entry: "Jump with timestamp ..."  | ||||||
|  |    is the same as "Unknown (0x8) with timestamp ....". | ||||||
|  | 3. After header there is one of the following lines: | ||||||
|  |    1. "  % Key__  Description__  Value": map header.  After mapping header  | ||||||
|  |       follows a table which may contain comments and lines consisting of  | ||||||
|  |       "  +", key, description and |{msgpack-value}|.  Key is separated by at  | ||||||
|  |       least two spaces with description, description is separated by at least  | ||||||
|  |       two spaces with the value.  Each key in the map must be at most as wide  | ||||||
|  |       as "Key__" header: "Key" allows at most 3-byte keys, "Key__" allows at  | ||||||
|  |       most 5-byte keys.  If keys actually occupy less bytes then the rest is  | ||||||
|  |       filled with spaces.  Keys cannot be empty, end with spaces, contain two  | ||||||
|  |       consequent spaces inside of them or contain multibyte characters (use  | ||||||
|  |       "=" format if you need this).  Descriptions have the same restrictions  | ||||||
|  |       on width and contents, except that empty descriptions are allowed.   | ||||||
|  |       Description column may be omitted. | ||||||
|  |  | ||||||
|  |       When writing description is ignored.  Keys with values |msgpack#equal|  | ||||||
|  |       to default ones are ignored.  Order of keys is preserved.  All keys are  | ||||||
|  |       treated as strings (not binary strings). | ||||||
|  |  | ||||||
|  |       Note: specifically for buffer list entries it is allowed to have more  | ||||||
|  |       then one map header.  Each map header starts a new map entry inside  | ||||||
|  |       buffer list because ShaDa buffer list entry is an array of maps.  I.e. > | ||||||
|  |  | ||||||
|  |         Buffer list with timestamp 1970-01-01T00:00:00: | ||||||
|  |           % Key  Description  Value | ||||||
|  |           + f    file name    "/foo" | ||||||
|  |           + l    line number  1 | ||||||
|  |           + c    column       10 | ||||||
|  | < | ||||||
|  |       is equivalent to > | ||||||
|  |  | ||||||
|  |         Buffer list with timestamp 1970-01-01T00:00:00: | ||||||
|  |           = [{="f": "/foo", ="c": 10}] | ||||||
|  | < | ||||||
|  |       and > | ||||||
|  |  | ||||||
|  |         Buffer list with timestamp 1970-01-01T00:00:00: | ||||||
|  |           % Key  Description  Value | ||||||
|  |           + f    file name    "/foo" | ||||||
|  |  | ||||||
|  |           % Key  Description  Value | ||||||
|  |           + f    file name    "/bar" | ||||||
|  | < | ||||||
|  |       is equivalent to > | ||||||
|  |  | ||||||
|  |         Buffer list with timestamp 1970-01-01T00:00:00: | ||||||
|  |           = [{="f": "/foo"}, {="f": "/bar"}] | ||||||
|  | < | ||||||
|  |       Note 2: specifically for register entries special syntax for arrays was  | ||||||
|  |       designed: > | ||||||
|  |  | ||||||
|  |         Register with timestamp 1970-01-01T00:00:00: | ||||||
|  |           % Key  Description  Value | ||||||
|  |           + rc   contents     @ | ||||||
|  |           | - "line1" | ||||||
|  |           | - "line2" | ||||||
|  | < | ||||||
|  |       This is equivalent to > | ||||||
|  |  | ||||||
|  |         Register with timestamp 1970-01-01T00:00:00: | ||||||
|  |           % Key  Description  Value | ||||||
|  |           + rc   contents     ["line1", "line2"] | ||||||
|  | < | ||||||
|  |       Such syntax is automatically used if array representation appears to be  | ||||||
|  |       too lengthy. | ||||||
|  |    2. "  @  Description__  Value": array header.  Same as map, but key is  | ||||||
|  |       omitted and description cannot be omitted.  Array entries start with  | ||||||
|  |       "  -". Example: > | ||||||
|  |  | ||||||
|  |         History entry with timestamp 1970-01-01T00:00:00: | ||||||
|  |           @ Description_  Value | ||||||
|  |           - history type  SEARCH | ||||||
|  |           - contents      "foo" | ||||||
|  |           - separator     '/' | ||||||
|  | < | ||||||
|  |       is equivalent to > | ||||||
|  |  | ||||||
|  |         History entry with timestamp 1970-01-01T00:00:00: | ||||||
|  |           = [SEARCH, "foo", '/'] | ||||||
|  | < | ||||||
|  |       Note: special array syntax for register entries is not recognized here. | ||||||
|  |    3. "  = {msgpack-value}": raw values.  |{msgpack-value}| in this case may  | ||||||
|  |       have absolutely any type.  Special array syntax for register entries is  | ||||||
|  |       not recognized here as well. | ||||||
|  |  | ||||||
|  |  | ||||||
| SQL							*ft-sql* | SQL							*ft-sql* | ||||||
|  |  | ||||||
| Since the text for this plugin is rather long it has been put in a separate | Since the text for this plugin is rather long it has been put in a separate | ||||||
|   | |||||||
							
								
								
									
										139
									
								
								runtime/doc/pi_msgpack.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								runtime/doc/pi_msgpack.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | |||||||
|  | *pi_msgpack.txt*	For NeoVim version 0.1. | ||||||
|  |  | ||||||
|  | Author:  Nikolay Pavlov <kp-pav@yandex.ru> | ||||||
|  | Copyright: (c) 2015 by Nikolay Pavlov | ||||||
|  |  | ||||||
|  | The Apache license applies to the files in this package, including  | ||||||
|  | runtime/autoload/msgpack.vim, runtime/doc/pi_msgpack.txt and  | ||||||
|  | test/functional/plugin/msgpack_spec.lua.  Like anything else that's free,  | ||||||
|  | msgpack.vim and its associated files are provided *as is* and comes with no  | ||||||
|  | warranty of any kind, either expressed or implied.  No guarantees of  | ||||||
|  | merchantability.  No guarantees of suitability for any purpose.  By using this  | ||||||
|  | plugin, you agree that in no event will the copyright holder be liable for any  | ||||||
|  | damages resulting from the use of this software. Use at your own risk! | ||||||
|  |  | ||||||
|  | ============================================================================== | ||||||
|  | 1. Contents				*msgpack.vim-contents* | ||||||
|  |  | ||||||
|  | 	1. Contents..............................: |msgpack.vim-contents| | ||||||
|  | 	2. Msgpack.vim introduction..............: |msgpack.vim-intro| | ||||||
|  | 	3. Msgpack.vim manual....................: |msgpack.vim-manual| | ||||||
|  | 	   Function arguments....................: |msgpack.vim-arguments| | ||||||
|  | 	   msgpack#is_int function...............: |msgpack#is_int()| | ||||||
|  | 	   msgpack#is_uint function..............: |msgpack#is_uint()| | ||||||
|  | 	   msgpack#strftime function.............: |msgpack#strftime()| | ||||||
|  | 	   msgpack#strptime function.............: |msgpack#strptime()| | ||||||
|  | 	   msgpack#int_dict_to_str function......: |msgpack#int_dict_to_str()| | ||||||
|  | 	   msgpack#special_type function.........: |msgpack#special_type()| | ||||||
|  | 	   msgpack#type function.................: |msgpack#type()| | ||||||
|  | 	   msgpack#deepcopy function.............: |msgpack#deepcopy()| | ||||||
|  | 	   msgpack#string function...............: |msgpack#string()| | ||||||
|  | 	   msgpack#eval function.................: |msgpack#eval()| | ||||||
|  | 	   msgpack#equal function................: |msgpack#equal()| | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ============================================================================== | ||||||
|  | 2. Msgpack.vim introduction			*msgpack.vim-intro* | ||||||
|  |  | ||||||
|  | This plugin contains utility functions to be used in conjunction with  | ||||||
|  | |msgpackdump()| and |msgpackparse()| functions. | ||||||
|  |  | ||||||
|  | ============================================================================== | ||||||
|  | 3. Msgpack.vim manual				*msgpack.vim-manual* | ||||||
|  |  | ||||||
|  | FUNCTION ARGUMENTS				*msgpack.vim-arguments* | ||||||
|  |  | ||||||
|  | Disambiguation of arguments described below.  Note: if e.g. function is listed  | ||||||
|  | as accepting |{msgpack-integer}| (or anything else) it means that function  | ||||||
|  | does not check whether argument matches its description. | ||||||
|  |  | ||||||
|  | *{msgpack-value}*	Either |msgpack-special-dict| or a regular value, but  | ||||||
|  | 			not function reference. | ||||||
|  | *{msgpack-integer}*	Any value for which |msgpack#type| will return  | ||||||
|  | 			"integer". | ||||||
|  | *{msgpack-special-int}*	|msgpack-special-dict| representing integer. | ||||||
|  |  | ||||||
|  | msgpack#is_int({msgpack-value})				*msgpack#is_int()* | ||||||
|  | 	Returns 1 if given {msgpack-value} is integer value, 0 otherwise. | ||||||
|  |  | ||||||
|  | msgpack#is_uint({msgpack-value})			*msgpack#is_uint()* | ||||||
|  | 	Returns 1 if given {msgpack-value} is integer value greater or equal  | ||||||
|  | 	to zero, 0 otherwise. | ||||||
|  |  | ||||||
|  | 							*msgpack#strftime* | ||||||
|  | msgpack#strftime({format}, {msgpack-integer})		*msgpack#strftime()* | ||||||
|  | 	Same as |strftime()|, but second argument may be  | ||||||
|  | 	|msgpack-special-dict|.  Requires |+python| or |+python3| to really  | ||||||
|  | 	work with |msgpack-special-dict|s. | ||||||
|  |  | ||||||
|  | 							*msgpack#strptime* | ||||||
|  | msgpack#strptime({format}, {time})			*msgpack#strptime()* | ||||||
|  | 	Reverse of |msgpack#strptime()|: for any time and format  | ||||||
|  | 	|msgpack#equal|( |msgpack#strptime|(format, |msgpack#strftime|(format,  | ||||||
|  | 	time)), time) be true.  Requires |+python| or |+python3|, without it  | ||||||
|  | 	only supports non-|msgpack-special-dict| nonnegative times and format  | ||||||
|  | 	equal to `%Y-%m-%dT%H:%M:%S`. | ||||||
|  |  | ||||||
|  | msgpack#int_dict_to_str({msgpack-special-int})	*msgpack#int_dict_to_str()* | ||||||
|  | 	Function which converts |msgpack-special-dict| integer value to  | ||||||
|  | 	a hexadecimal value like 0x1234567890ABCDEF (always returns exactly 16  | ||||||
|  | 	hexadecimal digits). | ||||||
|  |  | ||||||
|  | msgpack#special_type({msgpack-value})		*msgpack#special_type()* | ||||||
|  | 	Returns zero if {msgpack-value} is not |msgpack-special-dict|.  If it  | ||||||
|  | 	is it returns name of the key in |v:msgpack_types| which represents  | ||||||
|  | 	{msgpack-value} type. | ||||||
|  |  | ||||||
|  | msgpack#type({msgpack-value})				*msgpack#type()* | ||||||
|  | 	Returns name of the key in |v:msgpack_types| that represents  | ||||||
|  | 	{msgpack-value} type.  Never returns zero: this function returns  | ||||||
|  | 	msgpack type which will be dumped by |msgpackdump()| should it receive  | ||||||
|  | 	a list with singe {msgpack-value} as input. | ||||||
|  |  | ||||||
|  | msgpack#deepcopy({msgpack-value})			*msgpack#deepcopy()* | ||||||
|  | 	Like |deepcopy()|, but works correctly with |msgpack-special-dict|  | ||||||
|  | 	values.  Plain |deepcopy()| will destroy all types in  | ||||||
|  | 	|msgpack-special-dict| values because it will copy _TYPE key values,  | ||||||
|  | 	while they should be preserved. | ||||||
|  |  | ||||||
|  | msgpack#string({msgpack-value})				*msgpack#string()* | ||||||
|  | 	Like |string()|, but saves information about msgpack types.  Values  | ||||||
|  | 	dumped by msgpack#string may be read back by |msgpack#eval()|.   | ||||||
|  | 	Returns is the following: | ||||||
|  |  | ||||||
|  | 	- Dictionaries are dumped as "{key1: value1, key2: value2}". Note:  | ||||||
|  | 	  msgpack allows any values in keys, so with some  | ||||||
|  | 	  |msgpack-special-dict| values |msgpack#string()| may produce even  | ||||||
|  | 	  "{{1: 2}: 3, [4]: 5}". | ||||||
|  | 	- Lists are dumped as "[value1, value2]". | ||||||
|  | 	- Strings are dumped as | ||||||
|  | 	  1. `"abc"`: binary string. | ||||||
|  | 	  2. `="abc"`: string. | ||||||
|  | 	  3. `+(10)"ext"`: extension strings (10 may be replaced with any  | ||||||
|  | 	     8-bit signed integer). | ||||||
|  | 	  Inside strings the following escape sequences may be present: "\0"  | ||||||
|  | 	  (represents NUL byte), "\n" (represents line feed) and "\""  | ||||||
|  | 	  (represents double quote). | ||||||
|  | 	- Floating-point and integer values are dumped using |string()| or  | ||||||
|  | 	  |msgpack#int_dict_to_str()|. | ||||||
|  | 	- Booleans are dumped as "TRUE" or "FALSE". | ||||||
|  | 	- Nil values are dumped as "NIL". | ||||||
|  |  | ||||||
|  | msgpack#eval({string}, {dict})				*msgpack#eval()* | ||||||
|  | 	Transforms string created by |msgpack#string()| into a value suitable  | ||||||
|  | 	for |msgpackdump()|.  Second argument allows adding special values  | ||||||
|  | 	that start with head characters (|/\h|) and contain only word  | ||||||
|  | 	characters (|/\w|).  Built-in special values are "TRUE", "FALSE",  | ||||||
|  | 	"NIL", "nan" and "inf" and they cannot be overridden.  Map values are  | ||||||
|  | 	always evaluated to |msgpack-special-dict| values, as well as  | ||||||
|  | 	hexadecimal digits.  When evaluating maps order of keys is preserved. | ||||||
|  |  | ||||||
|  | 							*msgpack#equal* | ||||||
|  | msgpack#equal({msgpack-value}, {msgpack-value})		*msgpack#equal()* | ||||||
|  | 	Returns 1 if given values are equal, 0 otherwise.  When comparing  | ||||||
|  | 	msgpack map values order of keys is ignored.  Comparing  | ||||||
|  | 	|msgpack-special-dict| with equivalent non-special-dict value  | ||||||
|  | 	evaluates to 1. | ||||||
|  |  | ||||||
|  | ============================================================================== | ||||||
|  | vim:tw=78:ts=8:ft=help:fdm=marker | ||||||
							
								
								
									
										18
									
								
								runtime/ftplugin/shada.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								runtime/ftplugin/shada.vim
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | if exists('b:did_ftplugin') | ||||||
|  |   finish | ||||||
|  | endif | ||||||
|  |  | ||||||
|  | let b:did_ftplugin = 1 | ||||||
|  |  | ||||||
|  | function! ShaDaIndent(lnum) | ||||||
|  |   if a:lnum == 1 || getline(a:lnum) =~# '\mwith timestamp.*:$' | ||||||
|  |     return 0 | ||||||
|  |   else | ||||||
|  |     return shiftwidth() | ||||||
|  |   endif | ||||||
|  | endfunction | ||||||
|  |  | ||||||
|  | setlocal expandtab tabstop=2 softtabstop=2 shiftwidth=2 | ||||||
|  | setlocal indentexpr=ShaDaIndent(v:lnum) indentkeys=<:>,o,O | ||||||
|  |  | ||||||
|  | let b:undo_ftplugin = 'setlocal et< ts< sts< sw< indentexpr< indentkeys<' | ||||||
							
								
								
									
										39
									
								
								runtime/plugin/shada.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								runtime/plugin/shada.vim
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | if exists('g:loaded_shada_plugin') | ||||||
|  |   finish | ||||||
|  | endif | ||||||
|  | let g:loaded_shada_plugin = 1 | ||||||
|  |  | ||||||
|  | augroup ShaDaCommands | ||||||
|  |   autocmd! | ||||||
|  |   autocmd BufReadCmd *.shada,*.shada.tmp.[a-z] | ||||||
|  |         \ :if !empty(v:cmdarg)|throw '++opt not supported'|endif | ||||||
|  |         \ |call setline('.', shada#get_strings(readfile(expand('<afile>'),'b'))) | ||||||
|  |         \ |setlocal filetype=shada | ||||||
|  |   autocmd FileReadCmd *.shada,*.shada.tmp.[a-z] | ||||||
|  |         \ :if !empty(v:cmdarg)|throw '++opt not supported'|endif | ||||||
|  |         \ |call append("'[", shada#get_strings(readfile(expand('<afile>'), 'b'))) | ||||||
|  |   autocmd BufWriteCmd *.shada,*.shada.tmp.[a-z] | ||||||
|  |         \ :if !empty(v:cmdarg)|throw '++opt not supported'|endif | ||||||
|  |         \ |if writefile(shada#get_binstrings(getline(1, '$')), | ||||||
|  |                        \expand('<afile>'), 'b') == 0 | ||||||
|  |         \ |  let &l:modified = (expand('<afile>') is# bufname(+expand('<abuf>')) | ||||||
|  |                                \? 0 | ||||||
|  |                                \: stridx(&cpoptions, '+') != -1) | ||||||
|  |         \ |endif | ||||||
|  |   autocmd FileWriteCmd *.shada,*.shada.tmp.[a-z] | ||||||
|  |         \ :if !empty(v:cmdarg)|throw '++opt not supported'|endif | ||||||
|  |         \ |call writefile( | ||||||
|  |               \shada#get_binstrings(getline(min([line("'["), line("']")]), | ||||||
|  |                                            \max([line("'["), line("']")]))), | ||||||
|  |               \expand('<afile>'), | ||||||
|  |               \'b') | ||||||
|  |   autocmd FileAppendCmd *.shada,*.shada.tmp.[a-z] | ||||||
|  |         \ :if !empty(v:cmdarg)|throw '++opt not supported'|endif | ||||||
|  |         \ |call writefile( | ||||||
|  |               \shada#get_binstrings(getline(min([line("'["), line("']")]), | ||||||
|  |                                            \max([line("'["), line("']")]))), | ||||||
|  |               \expand('<afile>'), | ||||||
|  |               \'ab') | ||||||
|  |   autocmd SourceCmd *.shada,*.shada.tmp.[a-z] | ||||||
|  |         \ :execute 'rshada' fnameescape(expand('<afile>')) | ||||||
|  | augroup END | ||||||
							
								
								
									
										125
									
								
								runtime/syntax/shada.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								runtime/syntax/shada.vim
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | if exists("b:current_syntax") | ||||||
|  |     finish | ||||||
|  | endif | ||||||
|  |  | ||||||
|  | syntax match ShaDaEntryHeader | ||||||
|  |       \ '^\u.\{-} with timestamp \d\{4}-\d\d-\d\dT\d\d:\d\d:\d\d:$' | ||||||
|  | syntax match ShaDaEntryName '^\u.\{-}\ze with' contained | ||||||
|  |       \ containedin=ShaDaEntryHeader | ||||||
|  | syntax match ShaDaEntryTimestamp 'timestamp \zs\d\{4}-\d\d-\d\dT\d\d:\d\d:\d\d' | ||||||
|  |       \ contained containedin=ShaDaEntryHeader | ||||||
|  | syntax match ShaDaEntryTimestampNumber '\d\+' contained | ||||||
|  |       \ containedin=ShaDaEntryTimestamp | ||||||
|  |  | ||||||
|  | syntax match ShaDaComment '^\s*#.*$' | ||||||
|  |  | ||||||
|  | syntax region ShaDaEntryMapLong start='^  % Key_*  Description_*  Value$' | ||||||
|  |       \ end='^  %\|^\S'me=s-1 contains=ShaDaComment,ShaDaEntryMapLongEntryStart | ||||||
|  | syntax region ShaDaEntryMapShort start='^  % Key_*  Value$' | ||||||
|  |       \ end='^  %\|^\S'me=s-1 contains=ShaDaComment,ShaDaEntryMapShortEntryStart | ||||||
|  | syntax match ShaDaEntryMapHeader '^  % Key_*  \(Description_*  \)\?Value$' | ||||||
|  |       \ contained containedin=ShaDaEntryMapLong,ShaDaEntryMapShort | ||||||
|  | syntax match ShaDaEntryMapLongEntryStart '^  + 'hs=e-2,he=e-1 | ||||||
|  |       \ nextgroup=ShaDaEntryMapLongKey | ||||||
|  | syntax match ShaDaEntryMapLongKey '\S\+  \+\ze\S'he=e-2 contained | ||||||
|  |       \ nextgroup=ShaDaEntryMapLongDescription | ||||||
|  | syntax match ShaDaEntryMapLongDescription '.\{-}  \ze\S'he=e-2 contained | ||||||
|  |       \ nextgroup=@ShaDaEntryMsgpackValue | ||||||
|  | syntax match ShaDaEntryMapShortEntryStart '^  + 'hs=e-2,he=e-1 contained | ||||||
|  |       \ nextgroup=ShaDaEntryMapShortKey | ||||||
|  | syntax match ShaDaEntryMapShortKey '\S\+  \+\ze\S'he=e-2 contained | ||||||
|  |       \ nextgroup=@ShaDaEntryMsgpackValue | ||||||
|  | syntax match ShaDaEntryMapBinArrayStart '^  | - 'hs=e-4,he=e-1 contained | ||||||
|  |       \ containedin=ShaDaEntryMapLong,ShaDaEntryMapShort | ||||||
|  |       \ nextgroup=@ShaDaEntryMsgpackValue | ||||||
|  |  | ||||||
|  | syntax region ShaDaEntryArray start='^  @ Description_*  Value$' | ||||||
|  |       \ end='^\S'me=s-1 keepend | ||||||
|  |       \ contains=ShaDaComment,ShaDaEntryArrayEntryStart,ShaDaEntryArrayHeader | ||||||
|  | syntax match ShaDaEntryArrayHeader '^  @ Description_*  Value$' contained | ||||||
|  | syntax match ShaDaEntryArrayEntryStart '^  - 'hs=e-2,he=e-1 | ||||||
|  |       \ nextgroup=ShaDaEntryArrayDescription | ||||||
|  | syntax match ShaDaEntryArrayDescription '.\{-}  \ze\S'he=e-2 contained | ||||||
|  |       \ nextgroup=@ShaDaEntryMsgpackValue | ||||||
|  |  | ||||||
|  | syntax match ShaDaEntryRawMsgpack '^  = ' nextgroup=@ShaDaEntryMsgpackValue | ||||||
|  |  | ||||||
|  | syntax cluster ShaDaEntryMsgpackValue | ||||||
|  |       \ add=ShaDaMsgpackKeyword,ShaDaMsgpackShaDaKeyword | ||||||
|  |       \ add=ShaDaMsgpackInteger,ShaDaMsgpackCharacter,ShaDaMsgpackFloat | ||||||
|  |       \ add=ShaDaMsgpackBinaryString,ShaDaMsgpackString,ShaDaMsgpackExt | ||||||
|  |       \ add=ShaDaMsgpackArray,ShaDaMsgpackMap | ||||||
|  |       \ add=ShaDaMsgpackMultilineArray | ||||||
|  | syntax keyword ShaDaMsgpackKeyword contained NIL TRUE FALSE | ||||||
|  | syntax keyword ShaDaMsgpackShaDaKeyword contained | ||||||
|  |       \ CMD SEARCH EXPR INPUT DEBUG | ||||||
|  |       \ CHARACTERWISE LINEWISE BLOCKWISE | ||||||
|  | syntax region ShaDaMsgpackBinaryString matchgroup=ShaDaMsgpackStringQuotes | ||||||
|  |       \ start='"' skip='\\"' end='"' contained keepend | ||||||
|  | syntax match ShaDaMsgpackBinaryStringEscape '\\[\\0n"]' | ||||||
|  |       \ contained containedin=ShaDaMsgpackBinaryString | ||||||
|  | syntax match ShaDaMsgpackString '=' contained nextgroup=ShaDaMsgpackBinaryString | ||||||
|  | syntax match ShaDaMsgpackExt '+(-\?\d\+)' contained | ||||||
|  |       \ nextgroup=ShaDaMsgpackBinaryString | ||||||
|  | syntax match ShaDaMsgpackExtType '-\?\d\+' contained containedin=ShaDaMsgpackExt | ||||||
|  | syntax match ShaDaMsgpackCharacter /'.'/ contained | ||||||
|  | syntax match ShaDaMsgpackInteger '-\?\%(0x\x\{,16}\|\d\+\)' contained | ||||||
|  | syntax match ShaDaMsgpackFloat '-\?\d\+\.\d\+\%(e[+-]\?\d\+\)\?' contained | ||||||
|  | syntax region ShaDaMsgpackArray matchgroup=ShaDaMsgpackArrayBraces | ||||||
|  |       \ start='\[' end='\]' contained | ||||||
|  |       \ contains=@ShaDaEntryMsgpackValue,ShaDaMsgpackComma | ||||||
|  | syntax region ShaDaMsgpackMap matchgroup=ShaDaMsgpackMapBraces | ||||||
|  |       \ start='{' end='}' contained | ||||||
|  |       \ contains=@ShaDaEntryMsgpackValue,ShaDaMsgpackComma,ShaDaMsgpackColon | ||||||
|  | syntax match ShaDaMsgpackComma ',' contained | ||||||
|  | syntax match ShaDaMsgpackColon ':' contained | ||||||
|  | syntax match ShaDaMsgpackMultilineArray '@' contained | ||||||
|  |  | ||||||
|  | hi def link ShaDaComment Comment | ||||||
|  | hi def link ShaDaEntryNumber Number | ||||||
|  | hi def link ShaDaEntryTimestamp Operator | ||||||
|  | hi def link ShaDaEntryName Keyword | ||||||
|  |  | ||||||
|  | hi def link ShaDaEntryMapHeader PreProc | ||||||
|  |  | ||||||
|  | hi def link ShaDaEntryMapEntryStart Label | ||||||
|  | hi def link ShaDaEntryMapLongEntryStart ShaDaEntryMapEntryStart | ||||||
|  | hi def link ShaDaEntryMapShortEntryStart ShaDaEntryMapEntryStart | ||||||
|  | hi def link ShaDaEntryMapBinArrayStart ShaDaEntryMapEntryStart | ||||||
|  | hi def link ShaDaEntryArrayEntryStart ShaDaEntryMapEntryStart | ||||||
|  |  | ||||||
|  | hi def link ShaDaEntryMapKey String | ||||||
|  | hi def link ShaDaEntryMapLongKey ShaDaEntryMapKey | ||||||
|  | hi def link ShaDaEntryMapShortKey ShaDaEntryMapKey | ||||||
|  |  | ||||||
|  | hi def link ShaDaEntryMapDescription Comment | ||||||
|  | hi def link ShaDaEntryMapLongDescription ShaDaEntryMapDescription | ||||||
|  | hi def link ShaDaEntryMapShortDescription ShaDaEntryMapDescription | ||||||
|  |  | ||||||
|  | hi def link ShaDaEntryArrayHeader PreProc | ||||||
|  |  | ||||||
|  | hi def link ShaDaEntryArrayDescription ShaDaEntryMapDescription | ||||||
|  |  | ||||||
|  | hi def link ShaDaMsgpackKeyword Keyword | ||||||
|  | hi def link ShaDaMsgpackShaDaKeyword ShaDaMsgpackKeyword | ||||||
|  | hi def link ShaDaMsgpackCharacter Character | ||||||
|  | hi def link ShaDaMsgpackInteger Number | ||||||
|  | hi def link ShaDaMsgpackFloat Float | ||||||
|  |  | ||||||
|  | hi def link ShaDaMsgpackBinaryString String | ||||||
|  | hi def link ShaDaMsgpackBinaryStringEscape SpecialChar | ||||||
|  | hi def link ShaDaMsgpackExtType Typedef | ||||||
|  |  | ||||||
|  | hi def link ShaDaMsgpackStringQuotes Operator | ||||||
|  | hi def link ShaDaMsgpackString ShaDaMsgpackStringQuotes | ||||||
|  | hi def link ShaDaMsgpackExt ShaDaMsgpackStringQuotes | ||||||
|  |  | ||||||
|  | hi def link ShaDaMsgpackMapBraces Operator | ||||||
|  | hi def link ShaDaMsgpackArrayBraces ShaDaMsgpackMapBraces | ||||||
|  |  | ||||||
|  | hi def link ShaDaMsgpackComma Operator | ||||||
|  | hi def link ShaDaMsgpackColon ShaDaMsgpackComma | ||||||
|  |  | ||||||
|  | hi def link ShaDaMsgpackMultilineArray Operator | ||||||
|  |  | ||||||
|  | let b:current_syntax = "shada" | ||||||
							
								
								
									
										41
									
								
								test/functional/plugin/helpers.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								test/functional/plugin/helpers.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | local paths = require('test.config.paths') | ||||||
|  |  | ||||||
|  | local helpers = require('test.functional.helpers') | ||||||
|  | local spawn, set_session, nvim_prog, merge_args = | ||||||
|  |   helpers.spawn, helpers.set_session, helpers.nvim_prog, helpers.merge_args | ||||||
|  |  | ||||||
|  | local additional_cmd = '' | ||||||
|  |  | ||||||
|  | local function nvim_argv(shada_file) | ||||||
|  |   local rtp_value = ('\'%s/runtime\''):format( | ||||||
|  |       paths.test_source_path:gsub('\'', '\'\'')) | ||||||
|  |   local nvim_argv = {nvim_prog, '-u', 'NORC', '-i', shada_file or 'NONE', '-N', | ||||||
|  |                      '--cmd', 'set shortmess+=I background=light noswapfile', | ||||||
|  |                      '--cmd', 'let &runtimepath=' .. rtp_value, | ||||||
|  |                      '--cmd', additional_cmd, | ||||||
|  |                      '--embed'} | ||||||
|  |   if helpers.prepend_argv then | ||||||
|  |     return merge_args(helpers.prepend_argv, nvim_argv) | ||||||
|  |   else | ||||||
|  |     return nvim_argv | ||||||
|  |   end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | local session = nil | ||||||
|  |  | ||||||
|  | local reset = function(...) | ||||||
|  |   if session then | ||||||
|  |     session:exit(0) | ||||||
|  |   end | ||||||
|  |   session = spawn(nvim_argv(...)) | ||||||
|  |   set_session(session) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | local set_additional_cmd = function(s) | ||||||
|  |   additional_cmd = s | ||||||
|  | end | ||||||
|  |  | ||||||
|  | return { | ||||||
|  |   reset=reset, | ||||||
|  |   set_additional_cmd=set_additional_cmd, | ||||||
|  | } | ||||||
							
								
								
									
										699
									
								
								test/functional/plugin/msgpack_spec.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										699
									
								
								test/functional/plugin/msgpack_spec.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,699 @@ | |||||||
|  | local helpers = require('test.functional.helpers') | ||||||
|  | local eq, nvim_eval, nvim_command, exc_exec = | ||||||
|  |   helpers.eq, helpers.eval, helpers.command, helpers.exc_exec | ||||||
|  |  | ||||||
|  | local plugin_helpers = require('test.functional.plugin.helpers') | ||||||
|  | local reset = plugin_helpers.reset | ||||||
|  |  | ||||||
|  | describe('In autoload/msgpack.vim', function() | ||||||
|  |   before_each(reset) | ||||||
|  |  | ||||||
|  |   local sp = function(typ, val) | ||||||
|  |     return ('{"_TYPE": v:msgpack_types.%s, "_VAL": %s}'):format(typ, val) | ||||||
|  |   end | ||||||
|  |   local mapsp = function(...) | ||||||
|  |     local val = '' | ||||||
|  |     for i=1,(select('#', ...)/2) do | ||||||
|  |       val = ('%s[%s,%s],'):format(val, select(i * 2 - 1, ...), | ||||||
|  |                                   select(i * 2, ...)) | ||||||
|  |     end | ||||||
|  |     return sp('map', '[' .. val .. ']') | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   local nan = -(1.0/0.0-1.0/0.0) | ||||||
|  |   local minus_nan = 1.0/0.0-1.0/0.0 | ||||||
|  |   local inf = 1.0/0.0 | ||||||
|  |   local minus_inf = -(1.0/0.0) | ||||||
|  |   local has_minus_nan = tostring(nan) ~= tostring(minus_nan) | ||||||
|  |  | ||||||
|  |   describe('function msgpack#equal', function() | ||||||
|  |     local msgpack_eq = function(expected, a, b) | ||||||
|  |       eq(expected, nvim_eval(('msgpack#equal(%s, %s)'):format(a, b))) | ||||||
|  |       if a ~= b then | ||||||
|  |         eq(expected, nvim_eval(('msgpack#equal(%s, %s)'):format(b, a))) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |     it('compares raw integers correctly', function() | ||||||
|  |       msgpack_eq(1, '1', '1') | ||||||
|  |       msgpack_eq(0, '1', '0') | ||||||
|  |     end) | ||||||
|  |     it('compares integer specials correctly', function() | ||||||
|  |       msgpack_eq(1, sp('integer', '[-1, 1, 0, 0]'), | ||||||
|  |                     sp('integer', '[-1, 1, 0, 0]')) | ||||||
|  |       msgpack_eq(0, sp('integer', '[-1, 1, 0, 0]'), | ||||||
|  |                     sp('integer', '[ 1, 1, 0, 0]')) | ||||||
|  |     end) | ||||||
|  |     it('compares integer specials with raw integer correctly', function() | ||||||
|  |       msgpack_eq(1, sp('integer', '[-1, 0, 0, 1]'), '-1') | ||||||
|  |       msgpack_eq(0, sp('integer', '[-1, 0, 0, 1]'), '1') | ||||||
|  |       msgpack_eq(0, sp('integer', '[ 1, 0, 0, 1]'), '-1') | ||||||
|  |       msgpack_eq(1, sp('integer', '[ 1, 0, 0, 1]'), '1') | ||||||
|  |     end) | ||||||
|  |     it('compares integer with float correctly', function() | ||||||
|  |       msgpack_eq(0, '0', '0.0') | ||||||
|  |     end) | ||||||
|  |     it('compares raw binaries correctly', function() | ||||||
|  |       msgpack_eq(1, '"abc\\ndef"', '"abc\\ndef"') | ||||||
|  |       msgpack_eq(0, '"abc\\ndef"', '"abc\\nghi"') | ||||||
|  |     end) | ||||||
|  |     it('compares binary specials correctly', function() | ||||||
|  |       msgpack_eq(1, sp('binary', '["abc\\n", "def"]'), | ||||||
|  |                     sp('binary', '["abc\\n", "def"]')) | ||||||
|  |       msgpack_eq(0, sp('binary', '["abc", "def"]'), | ||||||
|  |                     sp('binary', '["abc\\n", "def"]')) | ||||||
|  |     end) | ||||||
|  |     it('compares binary specials with raw binaries correctly', function() | ||||||
|  |       msgpack_eq(1, sp('binary', '["abc", "def"]'), '"abc\\ndef"') | ||||||
|  |       msgpack_eq(0, sp('binary', '["abc", "def"]'), '"abcdef"') | ||||||
|  |     end) | ||||||
|  |     it('compares string specials correctly', function() | ||||||
|  |       msgpack_eq(1, sp('string', '["abc\\n", "def"]'), | ||||||
|  |                     sp('string', '["abc\\n", "def"]')) | ||||||
|  |       msgpack_eq(0, sp('string', '["abc", "def"]'), | ||||||
|  |                     sp('string', '["abc\\n", "def"]')) | ||||||
|  |     end) | ||||||
|  |     it('compares string specials with binary correctly', function() | ||||||
|  |       msgpack_eq(0, sp('string', '["abc\\n", "def"]'), | ||||||
|  |                     sp('binary', '["abc\\n", "def"]')) | ||||||
|  |       msgpack_eq(0, sp('string', '["abc", "def"]'), '"abc\\ndef"') | ||||||
|  |       msgpack_eq(0, sp('binary', '["abc\\n", "def"]'), | ||||||
|  |                     sp('string', '["abc\\n", "def"]')) | ||||||
|  |       msgpack_eq(0, '"abc\\ndef"', sp('string', '["abc", "def"]')) | ||||||
|  |     end) | ||||||
|  |     it('compares ext specials correctly', function() | ||||||
|  |       msgpack_eq(1, sp('ext', '[1, ["", "ac"]]'), sp('ext', '[1, ["", "ac"]]')) | ||||||
|  |       msgpack_eq(0, sp('ext', '[2, ["", "ac"]]'), sp('ext', '[1, ["", "ac"]]')) | ||||||
|  |       msgpack_eq(0, sp('ext', '[1, ["", "ac"]]'), sp('ext', '[1, ["", "abc"]]')) | ||||||
|  |     end) | ||||||
|  |     it('compares raw maps correctly', function() | ||||||
|  |       msgpack_eq(1, '{"a": 1, "b": 2}', '{"b": 2, "a": 1}') | ||||||
|  |       msgpack_eq(1, '{}', '{}') | ||||||
|  |       msgpack_eq(0, '{}', '{"a": 1}') | ||||||
|  |       msgpack_eq(0, '{"a": 2}', '{"a": 1}') | ||||||
|  |       msgpack_eq(0, '{"a": 1}', '{"b": 1}') | ||||||
|  |       msgpack_eq(0, '{"a": 1}', '{"a": 1, "b": 1}') | ||||||
|  |       msgpack_eq(0, '{"a": 1, "b": 1}', '{"b": 1}') | ||||||
|  |     end) | ||||||
|  |     it('compares map specials correctly', function() | ||||||
|  |       msgpack_eq(1, mapsp(), mapsp()) | ||||||
|  |       msgpack_eq(1, mapsp(sp('binary', '[""]'), '""'), | ||||||
|  |                     mapsp(sp('binary', '[""]'), '""')) | ||||||
|  |       msgpack_eq(1, mapsp(mapsp('1', '1'), mapsp('1', '1')), | ||||||
|  |                     mapsp(mapsp('1', '1'), mapsp('1', '1'))) | ||||||
|  |       msgpack_eq(0, mapsp(), mapsp('1', '1')) | ||||||
|  |       msgpack_eq(0, mapsp(sp('binary', '["a"]'), '""'), | ||||||
|  |                     mapsp(sp('binary', '[""]'), '""')) | ||||||
|  |       msgpack_eq(0, mapsp(sp('binary', '[""]'), '"a"'), | ||||||
|  |                     mapsp(sp('binary', '[""]'), '""')) | ||||||
|  |       msgpack_eq(0, mapsp(sp('binary', '["a"]'), '"a"'), | ||||||
|  |                     mapsp(sp('binary', '[""]'), '""')) | ||||||
|  |       msgpack_eq(0, mapsp(mapsp('1', '1'), mapsp('1', '1')), | ||||||
|  |                     mapsp(sp('binary', '[""]'), mapsp('1', '1'))) | ||||||
|  |       msgpack_eq(0, mapsp(mapsp('1', '1'), mapsp('1', '1')), | ||||||
|  |                     mapsp(mapsp('2', '1'), mapsp('1', '1'))) | ||||||
|  |       msgpack_eq(0, mapsp(mapsp('1', '1'), mapsp('1', '1')), | ||||||
|  |                     mapsp(mapsp('1', '2'), mapsp('1', '1'))) | ||||||
|  |       msgpack_eq(0, mapsp(mapsp('1', '1'), mapsp('1', '1')), | ||||||
|  |                     mapsp(mapsp('1', '1'), mapsp('2', '1'))) | ||||||
|  |       msgpack_eq(0, mapsp(mapsp('1', '1'), mapsp('1', '1')), | ||||||
|  |                     mapsp(mapsp('1', '1'), mapsp('1', '2'))) | ||||||
|  |       msgpack_eq(1, mapsp(mapsp('2', '1'), mapsp('1', '1'), | ||||||
|  |                           mapsp('1', '1'), mapsp('1', '1')), | ||||||
|  |                     mapsp(mapsp('1', '1'), mapsp('1', '1'), | ||||||
|  |                           mapsp('2', '1'), mapsp('1', '1'))) | ||||||
|  |     end) | ||||||
|  |     it('compares map specials with raw maps correctly', function() | ||||||
|  |       msgpack_eq(1, mapsp(), '{}') | ||||||
|  |       msgpack_eq(1, mapsp(sp('string', '["1"]'), '1'), '{"1": 1}') | ||||||
|  |       msgpack_eq(1, mapsp(sp('string', '["1"]'), sp('integer', '[1, 0, 0, 1]')), | ||||||
|  |                     '{"1": 1}') | ||||||
|  |       msgpack_eq(0, mapsp(sp('integer', '[1, 0, 0, 1]'), sp('string', '["1"]')), | ||||||
|  |                     '{1: "1"}') | ||||||
|  |       msgpack_eq(0, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), | ||||||
|  |                     '{"1": 1}') | ||||||
|  |       msgpack_eq(0, | ||||||
|  |                  mapsp(sp('string', '["1"]'), '1', sp('string', '["2"]'), '2'), | ||||||
|  |                  '{"1": 1}') | ||||||
|  |       msgpack_eq(0, mapsp(sp('string', '["1"]'), '1'), '{"1": 1, "2": 2}') | ||||||
|  |     end) | ||||||
|  |     it('compares raw arrays correctly', function() | ||||||
|  |       msgpack_eq(1, '[]', '[]') | ||||||
|  |       msgpack_eq(0, '[]', '[1]') | ||||||
|  |       msgpack_eq(1, '[1]', '[1]') | ||||||
|  |       msgpack_eq(1, '[[[1]]]', '[[[1]]]') | ||||||
|  |       msgpack_eq(0, '[[[2]]]', '[[[1]]]') | ||||||
|  |     end) | ||||||
|  |     it('compares array specials correctly', function() | ||||||
|  |       msgpack_eq(1, sp('array', '[]'), sp('array', '[]')) | ||||||
|  |       msgpack_eq(0, sp('array', '[]'), sp('array', '[1]')) | ||||||
|  |       msgpack_eq(1, sp('array', '[1]'), sp('array', '[1]')) | ||||||
|  |       msgpack_eq(1, sp('array', '[[[1]]]'), sp('array', '[[[1]]]')) | ||||||
|  |       msgpack_eq(0, sp('array', '[[[1]]]'), sp('array', '[[[2]]]')) | ||||||
|  |     end) | ||||||
|  |     it('compares array specials with raw arrays correctly', function() | ||||||
|  |       msgpack_eq(1, sp('array', '[]'), '[]') | ||||||
|  |       msgpack_eq(0, sp('array', '[]'), '[1]') | ||||||
|  |       msgpack_eq(1, sp('array', '[1]'), '[1]') | ||||||
|  |       msgpack_eq(1, sp('array', '[[[1]]]'), '[[[1]]]') | ||||||
|  |       msgpack_eq(0, sp('array', '[[[1]]]'), '[[[2]]]') | ||||||
|  |     end) | ||||||
|  |     it('compares raw floats correctly', function() | ||||||
|  |       msgpack_eq(1, '0.0', '0.0') | ||||||
|  |       msgpack_eq(1, '(1.0/0.0-1.0/0.0)', '(1.0/0.0-1.0/0.0)') | ||||||
|  |       if has_minus_nan then | ||||||
|  |         msgpack_eq(0, '(1.0/0.0-1.0/0.0)', '-(1.0/0.0-1.0/0.0)') | ||||||
|  |       end | ||||||
|  |       msgpack_eq(1, '-(1.0/0.0-1.0/0.0)', '-(1.0/0.0-1.0/0.0)') | ||||||
|  |       msgpack_eq(1, '1.0/0.0', '1.0/0.0') | ||||||
|  |       msgpack_eq(1, '-(1.0/0.0)', '-(1.0/0.0)') | ||||||
|  |       msgpack_eq(1, '0.0', '0.0') | ||||||
|  |       msgpack_eq(0, '0.0', '1.0') | ||||||
|  |       msgpack_eq(0, '0.0', '(1.0/0.0-1.0/0.0)') | ||||||
|  |       msgpack_eq(0, '0.0', '1.0/0.0') | ||||||
|  |       msgpack_eq(0, '0.0', '-(1.0/0.0)') | ||||||
|  |       msgpack_eq(0, '1.0/0.0', '-(1.0/0.0)') | ||||||
|  |       msgpack_eq(0, '(1.0/0.0-1.0/0.0)', '-(1.0/0.0)') | ||||||
|  |       msgpack_eq(0, '(1.0/0.0-1.0/0.0)', '1.0/0.0') | ||||||
|  |     end) | ||||||
|  |     it('compares float specials with raw floats correctly', function() | ||||||
|  |       msgpack_eq(1, sp('float', '0.0'), '0.0') | ||||||
|  |       msgpack_eq(1, sp('float', '(1.0/0.0-1.0/0.0)'), '(1.0/0.0-1.0/0.0)') | ||||||
|  |       if has_minus_nan then | ||||||
|  |         msgpack_eq(0, sp('float', '(1.0/0.0-1.0/0.0)'), '-(1.0/0.0-1.0/0.0)') | ||||||
|  |         msgpack_eq(0, sp('float', '-(1.0/0.0-1.0/0.0)'), '(1.0/0.0-1.0/0.0)') | ||||||
|  |       end | ||||||
|  |       msgpack_eq(1, sp('float', '-(1.0/0.0-1.0/0.0)'), '-(1.0/0.0-1.0/0.0)') | ||||||
|  |       msgpack_eq(1, sp('float', '1.0/0.0'), '1.0/0.0') | ||||||
|  |       msgpack_eq(1, sp('float', '-(1.0/0.0)'), '-(1.0/0.0)') | ||||||
|  |       msgpack_eq(1, sp('float', '0.0'), '0.0') | ||||||
|  |       msgpack_eq(0, sp('float', '0.0'), '1.0') | ||||||
|  |       msgpack_eq(0, sp('float', '0.0'), '(1.0/0.0-1.0/0.0)') | ||||||
|  |       msgpack_eq(0, sp('float', '0.0'), '1.0/0.0') | ||||||
|  |       msgpack_eq(0, sp('float', '0.0'), '-(1.0/0.0)') | ||||||
|  |       msgpack_eq(0, sp('float', '1.0/0.0'), '-(1.0/0.0)') | ||||||
|  |       msgpack_eq(0, sp('float', '(1.0/0.0-1.0/0.0)'), '-(1.0/0.0)') | ||||||
|  |       msgpack_eq(0, sp('float', '(1.0/0.0-1.0/0.0)'), '1.0/0.0') | ||||||
|  |     end) | ||||||
|  |     it('compares float specials correctly', function() | ||||||
|  |       msgpack_eq(1, sp('float', '0.0'), sp('float', '0.0')) | ||||||
|  |       msgpack_eq(1, sp('float', '(1.0/0.0-1.0/0.0)'), | ||||||
|  |                     sp('float', '(1.0/0.0-1.0/0.0)')) | ||||||
|  |       msgpack_eq(1, sp('float', '1.0/0.0'), sp('float', '1.0/0.0')) | ||||||
|  |       msgpack_eq(1, sp('float', '-(1.0/0.0)'), sp('float', '-(1.0/0.0)')) | ||||||
|  |       msgpack_eq(1, sp('float', '0.0'), sp('float', '0.0')) | ||||||
|  |       msgpack_eq(0, sp('float', '0.0'), sp('float', '1.0')) | ||||||
|  |       msgpack_eq(0, sp('float', '0.0'), sp('float', '(1.0/0.0-1.0/0.0)')) | ||||||
|  |       msgpack_eq(0, sp('float', '0.0'), sp('float', '1.0/0.0')) | ||||||
|  |       msgpack_eq(0, sp('float', '0.0'), sp('float', '-(1.0/0.0)')) | ||||||
|  |       msgpack_eq(0, sp('float', '1.0/0.0'), sp('float', '-(1.0/0.0)')) | ||||||
|  |       msgpack_eq(0, sp('float', '(1.0/0.0-1.0/0.0)'), sp('float', '-(1.0/0.0)')) | ||||||
|  |       if has_minus_nan then | ||||||
|  |         msgpack_eq(0, sp('float', '(1.0/0.0-1.0/0.0)'), | ||||||
|  |                       sp('float', '-(1.0/0.0-1.0/0.0)')) | ||||||
|  |       end | ||||||
|  |       msgpack_eq(1, sp('float', '-(1.0/0.0-1.0/0.0)'), | ||||||
|  |                     sp('float', '-(1.0/0.0-1.0/0.0)')) | ||||||
|  |       msgpack_eq(0, sp('float', '(1.0/0.0-1.0/0.0)'), sp('float', '1.0/0.0')) | ||||||
|  |     end) | ||||||
|  |     it('compares boolean specials correctly', function() | ||||||
|  |       msgpack_eq(1, sp('boolean', '1'), sp('boolean', '1')) | ||||||
|  |       msgpack_eq(0, sp('boolean', '1'), sp('boolean', '0')) | ||||||
|  |     end) | ||||||
|  |     it('compares nil specials correctly', function() | ||||||
|  |       msgpack_eq(1, sp('nil', '1'), sp('nil', '0')) | ||||||
|  |     end) | ||||||
|  |     it('compares nil, boolean and integer values with each other correctly', | ||||||
|  |     function() | ||||||
|  |       msgpack_eq(0, sp('boolean', '1'), '1') | ||||||
|  |       msgpack_eq(0, sp('boolean', '1'), sp('nil', '0')) | ||||||
|  |       msgpack_eq(0, sp('boolean', '1'), sp('nil', '1')) | ||||||
|  |       msgpack_eq(0, sp('boolean', '0'), sp('nil', '0')) | ||||||
|  |       msgpack_eq(0, sp('boolean', '0'), '0') | ||||||
|  |       msgpack_eq(0, sp('boolean', '0'), sp('integer', '[1, 0, 0, 0]')) | ||||||
|  |       msgpack_eq(0, sp('boolean', '0'), sp('integer', '[1, 0, 0, 1]')) | ||||||
|  |       msgpack_eq(0, sp('boolean', '1'), sp('integer', '[1, 0, 0, 1]')) | ||||||
|  |       msgpack_eq(0, sp('nil', '0'), sp('integer', '[1, 0, 0, 0]')) | ||||||
|  |       msgpack_eq(0, sp('nil', '0'), '0') | ||||||
|  |     end) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   describe('function msgpack#is_int', function() | ||||||
|  |     it('works', function() | ||||||
|  |       eq(1, nvim_eval('msgpack#is_int(1)')) | ||||||
|  |       eq(1, nvim_eval('msgpack#is_int(-1)')) | ||||||
|  |       eq(1, nvim_eval(('msgpack#is_int(%s)'):format( | ||||||
|  |           sp('integer', '[1, 0, 0, 1]')))) | ||||||
|  |       eq(1, nvim_eval(('msgpack#is_int(%s)'):format( | ||||||
|  |           sp('integer', '[-1, 0, 0, 1]')))) | ||||||
|  |       eq(0, nvim_eval(('msgpack#is_int(%s)'):format( | ||||||
|  |           sp('float', '0.0')))) | ||||||
|  |       eq(0, nvim_eval(('msgpack#is_int(%s)'):format( | ||||||
|  |           sp('boolean', '0')))) | ||||||
|  |       eq(0, nvim_eval(('msgpack#is_int(%s)'):format( | ||||||
|  |           sp('nil', '0')))) | ||||||
|  |       eq(0, nvim_eval('msgpack#is_int("")')) | ||||||
|  |     end) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   describe('function msgpack#is_uint', function() | ||||||
|  |     it('works', function() | ||||||
|  |       eq(1, nvim_eval('msgpack#is_uint(1)')) | ||||||
|  |       eq(0, nvim_eval('msgpack#is_uint(-1)')) | ||||||
|  |       eq(1, nvim_eval(('msgpack#is_uint(%s)'):format( | ||||||
|  |           sp('integer', '[1, 0, 0, 1]')))) | ||||||
|  |       eq(0, nvim_eval(('msgpack#is_uint(%s)'):format( | ||||||
|  |           sp('integer', '[-1, 0, 0, 1]')))) | ||||||
|  |       eq(0, nvim_eval(('msgpack#is_uint(%s)'):format( | ||||||
|  |           sp('float', '0.0')))) | ||||||
|  |       eq(0, nvim_eval(('msgpack#is_uint(%s)'):format( | ||||||
|  |           sp('boolean', '0')))) | ||||||
|  |       eq(0, nvim_eval(('msgpack#is_uint(%s)'):format( | ||||||
|  |           sp('nil', '0')))) | ||||||
|  |       eq(0, nvim_eval('msgpack#is_uint("")')) | ||||||
|  |     end) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   describe('function msgpack#strftime', function() | ||||||
|  |     it('works', function() | ||||||
|  |       local epoch = os.date('%Y-%m-%dT%H:%M:%S', 0) | ||||||
|  |       eq(epoch, nvim_eval('msgpack#strftime("%Y-%m-%dT%H:%M:%S", 0)')) | ||||||
|  |       eq(epoch, nvim_eval( | ||||||
|  |           ('msgpack#strftime("%%Y-%%m-%%dT%%H:%%M:%%S", %s)'):format(sp( | ||||||
|  |               'integer', '[1, 0, 0, 0]')))) | ||||||
|  |     end) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   describe('function msgpack#strptime', function() | ||||||
|  |     it('works', function() | ||||||
|  |       for _, v in ipairs({0, 10, 100000, 204, 1000000000}) do | ||||||
|  |         local time = os.date('%Y-%m-%dT%H:%M:%S', v) | ||||||
|  |         eq(v, nvim_eval('msgpack#strptime("%Y-%m-%dT%H:%M:%S", ' | ||||||
|  |                                       .. '"' .. time .. '")')) | ||||||
|  |       end | ||||||
|  |     end) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   describe('function msgpack#type', function() | ||||||
|  |     local type_eq = function(expected, val) | ||||||
|  |       eq(expected, nvim_eval(('msgpack#type(%s)'):format(val))) | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     it('works for special dictionaries', function() | ||||||
|  |       type_eq('string', sp('string', '[""]')) | ||||||
|  |       type_eq('binary', sp('binary', '[""]')) | ||||||
|  |       type_eq('ext', sp('ext', '[1, [""]]')) | ||||||
|  |       type_eq('array', sp('array', '[]')) | ||||||
|  |       type_eq('map', sp('map', '[]')) | ||||||
|  |       type_eq('integer', sp('integer', '[1, 0, 0, 0]')) | ||||||
|  |       type_eq('float', sp('float', '0.0')) | ||||||
|  |       type_eq('boolean', sp('boolean', '0')) | ||||||
|  |       type_eq('nil', sp('nil', '0')) | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('works for regular values', function() | ||||||
|  |       type_eq('binary', '""') | ||||||
|  |       type_eq('array', '[]') | ||||||
|  |       type_eq('map', '{}') | ||||||
|  |       type_eq('integer', '1') | ||||||
|  |       type_eq('float', '0.0') | ||||||
|  |       type_eq('float', '(1.0/0.0)') | ||||||
|  |       type_eq('float', '-(1.0/0.0)') | ||||||
|  |       type_eq('float', '(1.0/0.0-1.0/0.0)') | ||||||
|  |     end) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   describe('function msgpack#special_type', function() | ||||||
|  |     local sp_type_eq = function(expected, val) | ||||||
|  |       eq(expected, nvim_eval(('msgpack#special_type(%s)'):format(val))) | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     it('works for special dictionaries', function() | ||||||
|  |       sp_type_eq('string', sp('string', '[""]')) | ||||||
|  |       sp_type_eq('binary', sp('binary', '[""]')) | ||||||
|  |       sp_type_eq('ext', sp('ext', '[1, [""]]')) | ||||||
|  |       sp_type_eq('array', sp('array', '[]')) | ||||||
|  |       sp_type_eq('map', sp('map', '[]')) | ||||||
|  |       sp_type_eq('integer', sp('integer', '[1, 0, 0, 0]')) | ||||||
|  |       sp_type_eq('float', sp('float', '0.0')) | ||||||
|  |       sp_type_eq('boolean', sp('boolean', '0')) | ||||||
|  |       sp_type_eq('nil', sp('nil', '0')) | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('works for regular values', function() | ||||||
|  |       sp_type_eq(0, '""') | ||||||
|  |       sp_type_eq(0, '[]') | ||||||
|  |       sp_type_eq(0, '{}') | ||||||
|  |       sp_type_eq(0, '1') | ||||||
|  |       sp_type_eq(0, '0.0') | ||||||
|  |       sp_type_eq(0, '(1.0/0.0)') | ||||||
|  |       sp_type_eq(0, '-(1.0/0.0)') | ||||||
|  |       sp_type_eq(0, '(1.0/0.0-1.0/0.0)') | ||||||
|  |     end) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   describe('function msgpack#string', function() | ||||||
|  |     local string_eq = function(expected, val) | ||||||
|  |       eq(expected, nvim_eval(('msgpack#string(%s)'):format(val))) | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     it('works for special dictionaries', function() | ||||||
|  |       string_eq('=""', sp('string', '[""]')) | ||||||
|  |       string_eq('="\\n"', sp('string', '["", ""]')) | ||||||
|  |       string_eq('="ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]')) | ||||||
|  |       string_eq('""', sp('binary', '[""]')) | ||||||
|  |       string_eq('"\\n"', sp('binary', '["", ""]')) | ||||||
|  |       string_eq('"ab\\0c\\nde"', sp('binary', '["ab\\nc", "de"]')) | ||||||
|  |       string_eq('+(2)""', sp('ext', '[2, [""]]')) | ||||||
|  |       string_eq('+(2)"\\n"', sp('ext', '[2, ["", ""]]')) | ||||||
|  |       string_eq('+(2)"ab\\0c\\nde"', sp('ext', '[2, ["ab\\nc", "de"]]')) | ||||||
|  |       string_eq('[]', sp('array', '[]')) | ||||||
|  |       string_eq('[[[[{}]]]]', sp('array', '[[[[{}]]]]')) | ||||||
|  |       string_eq('{}', sp('map', '[]')) | ||||||
|  |       string_eq('{2: 10}', sp('map', '[[2, 10]]')) | ||||||
|  |       string_eq('{{1: 1}: {1: 1}, {2: 1}: {1: 1}}', | ||||||
|  |                 mapsp(mapsp('2', '1'), mapsp('1', '1'), | ||||||
|  |                       mapsp('1', '1'), mapsp('1', '1'))) | ||||||
|  |       string_eq('{{1: 1}: {1: 1}, {2: 1}: {1: 1}}', | ||||||
|  |                 mapsp(mapsp('1', '1'), mapsp('1', '1'), | ||||||
|  |                       mapsp('2', '1'), mapsp('1', '1'))) | ||||||
|  |       string_eq('{[1, 2, {{1: 2}: 1}]: [1, 2, {{1: 2}: 1}]}', | ||||||
|  |                 mapsp(('[1, 2, %s]'):format(mapsp(mapsp('1', '2'), '1')), | ||||||
|  |                       ('[1, 2, %s]'):format(mapsp(mapsp('1', '2'), '1')))) | ||||||
|  |       string_eq('0x0000000000000000', sp('integer', '[1, 0, 0, 0]')) | ||||||
|  |       string_eq('-0x0000000100000000', sp('integer', '[-1, 0, 2, 0]')) | ||||||
|  |       string_eq('0x123456789abcdef0', | ||||||
|  |                 sp('integer', '[ 1, 0,  610839793, 448585456]')) | ||||||
|  |       string_eq('-0x123456789abcdef0', | ||||||
|  |                 sp('integer', '[-1, 0,  610839793, 448585456]')) | ||||||
|  |       string_eq('0xf23456789abcdef0', | ||||||
|  |                 sp('integer', '[ 1, 3, 1684581617, 448585456]')) | ||||||
|  |       string_eq('-0x723456789abcdef0', | ||||||
|  |                 sp('integer', '[-1, 1, 1684581617, 448585456]')) | ||||||
|  |       string_eq('0.0', sp('float', '0.0')) | ||||||
|  |       string_eq('inf', sp('float', '(1.0/0.0)')) | ||||||
|  |       string_eq('-inf', sp('float', '-(1.0/0.0)')) | ||||||
|  |       if has_minus_nan then | ||||||
|  |         string_eq('-nan', sp('float', '(1.0/0.0-1.0/0.0)')) | ||||||
|  |       end | ||||||
|  |       string_eq('nan', sp('float', '-(1.0/0.0-1.0/0.0)')) | ||||||
|  |       string_eq('FALSE', sp('boolean', '0')) | ||||||
|  |       string_eq('TRUE', sp('boolean', '1')) | ||||||
|  |       string_eq('NIL', sp('nil', '0')) | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('works for regular values', function() | ||||||
|  |       string_eq('""', '""') | ||||||
|  |       string_eq('"\\n"', '"\\n"') | ||||||
|  |       string_eq('[]', '[]') | ||||||
|  |       string_eq('[[[{}]]]', '[[[{}]]]') | ||||||
|  |       string_eq('{}', '{}') | ||||||
|  |       string_eq('{="2": 10}', '{2: 10}') | ||||||
|  |       string_eq('{="2": [{}]}', '{2: [{}]}') | ||||||
|  |       string_eq('1', '1') | ||||||
|  |       string_eq('0.0', '0.0') | ||||||
|  |       string_eq('inf', '(1.0/0.0)') | ||||||
|  |       string_eq('-inf', '-(1.0/0.0)') | ||||||
|  |       if has_minus_nan then | ||||||
|  |         string_eq('-nan', '(1.0/0.0-1.0/0.0)') | ||||||
|  |       end | ||||||
|  |       string_eq('nan', '-(1.0/0.0-1.0/0.0)') | ||||||
|  |     end) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   describe('function msgpack#deepcopy', function() | ||||||
|  |     it('works for special dictionaries', function() | ||||||
|  |       nvim_command('let sparr = ' .. sp('array', '[[[]]]')) | ||||||
|  |       nvim_command('let spmap = ' .. mapsp('"abc"', '[[]]')) | ||||||
|  |       nvim_command('let spint = ' .. sp('integer', '[1, 0, 0, 0]')) | ||||||
|  |       nvim_command('let spflt = ' .. sp('float', '1.0')) | ||||||
|  |       nvim_command('let spext = ' .. sp('ext', '[2, ["abc", "def"]]')) | ||||||
|  |       nvim_command('let spstr = ' .. sp('string', '["abc", "def"]')) | ||||||
|  |       nvim_command('let spbin = ' .. sp('binary', '["abc", "def"]')) | ||||||
|  |       nvim_command('let spbln = ' .. sp('boolean', '0')) | ||||||
|  |       nvim_command('let spnil = ' .. sp('nil', '0')) | ||||||
|  |  | ||||||
|  |       nvim_command('let sparr2 = msgpack#deepcopy(sparr)') | ||||||
|  |       nvim_command('let spmap2 = msgpack#deepcopy(spmap)') | ||||||
|  |       nvim_command('let spint2 = msgpack#deepcopy(spint)') | ||||||
|  |       nvim_command('let spflt2 = msgpack#deepcopy(spflt)') | ||||||
|  |       nvim_command('let spext2 = msgpack#deepcopy(spext)') | ||||||
|  |       nvim_command('let spstr2 = msgpack#deepcopy(spstr)') | ||||||
|  |       nvim_command('let spbin2 = msgpack#deepcopy(spbin)') | ||||||
|  |       nvim_command('let spbln2 = msgpack#deepcopy(spbln)') | ||||||
|  |       nvim_command('let spnil2 = msgpack#deepcopy(spnil)') | ||||||
|  |  | ||||||
|  |       eq('array', nvim_eval('msgpack#type(sparr2)')) | ||||||
|  |       eq('map', nvim_eval('msgpack#type(spmap2)')) | ||||||
|  |       eq('integer', nvim_eval('msgpack#type(spint2)')) | ||||||
|  |       eq('float', nvim_eval('msgpack#type(spflt2)')) | ||||||
|  |       eq('ext', nvim_eval('msgpack#type(spext2)')) | ||||||
|  |       eq('string', nvim_eval('msgpack#type(spstr2)')) | ||||||
|  |       eq('binary', nvim_eval('msgpack#type(spbin2)')) | ||||||
|  |       eq('boolean', nvim_eval('msgpack#type(spbln2)')) | ||||||
|  |       eq('nil', nvim_eval('msgpack#type(spnil2)')) | ||||||
|  |  | ||||||
|  |       nvim_command('call add(sparr._VAL, 0)') | ||||||
|  |       nvim_command('call add(sparr._VAL[0], 0)') | ||||||
|  |       nvim_command('call add(sparr._VAL[0][0], 0)') | ||||||
|  |       nvim_command('call add(spmap._VAL, [0, 0])') | ||||||
|  |       nvim_command('call add(spmap._VAL[0][1], 0)') | ||||||
|  |       nvim_command('call add(spmap._VAL[0][1][0], 0)') | ||||||
|  |       nvim_command('let spint._VAL[1] = 1') | ||||||
|  |       nvim_command('let spflt._VAL = 0.0') | ||||||
|  |       nvim_command('let spext._VAL[0] = 3') | ||||||
|  |       nvim_command('let spext._VAL[1][0] = "gh"') | ||||||
|  |       nvim_command('let spstr._VAL[0] = "gh"') | ||||||
|  |       nvim_command('let spbin._VAL[0] = "gh"') | ||||||
|  |       nvim_command('let spbln._VAL = 1') | ||||||
|  |       nvim_command('let spnil._VAL = 1') | ||||||
|  |  | ||||||
|  |       eq({_TYPE={}, _VAL={{{}}}}, nvim_eval('sparr2')) | ||||||
|  |       eq({_TYPE={}, _VAL={{'abc', {{}}}}}, nvim_eval('spmap2')) | ||||||
|  |       eq({_TYPE={}, _VAL={1, 0, 0, 0}}, nvim_eval('spint2')) | ||||||
|  |       eq({_TYPE={}, _VAL=1.0}, nvim_eval('spflt2')) | ||||||
|  |       eq({_TYPE={}, _VAL={2, {'abc', 'def'}}}, nvim_eval('spext2')) | ||||||
|  |       eq({_TYPE={}, _VAL={'abc', 'def'}}, nvim_eval('spstr2')) | ||||||
|  |       eq({_TYPE={}, _VAL={'abc', 'def'}}, nvim_eval('spbin2')) | ||||||
|  |       eq({_TYPE={}, _VAL=0}, nvim_eval('spbln2')) | ||||||
|  |       eq({_TYPE={}, _VAL=0}, nvim_eval('spnil2')) | ||||||
|  |  | ||||||
|  |       nvim_command('let sparr._TYPE = []') | ||||||
|  |       nvim_command('let spmap._TYPE = []') | ||||||
|  |       nvim_command('let spint._TYPE = []') | ||||||
|  |       nvim_command('let spflt._TYPE = []') | ||||||
|  |       nvim_command('let spext._TYPE = []') | ||||||
|  |       nvim_command('let spstr._TYPE = []') | ||||||
|  |       nvim_command('let spbin._TYPE = []') | ||||||
|  |       nvim_command('let spbln._TYPE = []') | ||||||
|  |       nvim_command('let spnil._TYPE = []') | ||||||
|  |  | ||||||
|  |       eq('array', nvim_eval('msgpack#special_type(sparr2)')) | ||||||
|  |       eq('map', nvim_eval('msgpack#special_type(spmap2)')) | ||||||
|  |       eq('integer', nvim_eval('msgpack#special_type(spint2)')) | ||||||
|  |       eq('float', nvim_eval('msgpack#special_type(spflt2)')) | ||||||
|  |       eq('ext', nvim_eval('msgpack#special_type(spext2)')) | ||||||
|  |       eq('string', nvim_eval('msgpack#special_type(spstr2)')) | ||||||
|  |       eq('binary', nvim_eval('msgpack#special_type(spbin2)')) | ||||||
|  |       eq('boolean', nvim_eval('msgpack#special_type(spbln2)')) | ||||||
|  |       eq('nil', nvim_eval('msgpack#special_type(spnil2)')) | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('works for regular values', function() | ||||||
|  |       nvim_command('let arr = [[[]]]') | ||||||
|  |       nvim_command('let map = {1: {}}') | ||||||
|  |       nvim_command('let int = 1') | ||||||
|  |       nvim_command('let flt = 2.0') | ||||||
|  |       nvim_command('let bin = "abc"') | ||||||
|  |  | ||||||
|  |       nvim_command('let arr2 = msgpack#deepcopy(arr)') | ||||||
|  |       nvim_command('let map2 = msgpack#deepcopy(map)') | ||||||
|  |       nvim_command('let int2 = msgpack#deepcopy(int)') | ||||||
|  |       nvim_command('let flt2 = msgpack#deepcopy(flt)') | ||||||
|  |       nvim_command('let bin2 = msgpack#deepcopy(bin)') | ||||||
|  |  | ||||||
|  |       eq('array', nvim_eval('msgpack#type(arr2)')) | ||||||
|  |       eq('map', nvim_eval('msgpack#type(map2)')) | ||||||
|  |       eq('integer', nvim_eval('msgpack#type(int2)')) | ||||||
|  |       eq('float', nvim_eval('msgpack#type(flt2)')) | ||||||
|  |       eq('binary', nvim_eval('msgpack#type(bin2)')) | ||||||
|  |  | ||||||
|  |       nvim_command('call add(arr, 0)') | ||||||
|  |       nvim_command('call add(arr[0], 0)') | ||||||
|  |       nvim_command('call add(arr[0][0], 0)') | ||||||
|  |       nvim_command('let map.a = 1') | ||||||
|  |       nvim_command('let map.1.a = 1') | ||||||
|  |       nvim_command('let int = 2') | ||||||
|  |       nvim_command('let flt = 3.0') | ||||||
|  |       nvim_command('let bin = ""') | ||||||
|  |  | ||||||
|  |       eq({{{}}}, nvim_eval('arr2')) | ||||||
|  |       eq({['1']={}}, nvim_eval('map2')) | ||||||
|  |       eq(1, nvim_eval('int2')) | ||||||
|  |       eq(2.0, nvim_eval('flt2')) | ||||||
|  |       eq('abc', nvim_eval('bin2')) | ||||||
|  |     end) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   describe('function msgpack#eval', function() | ||||||
|  |     local eval_eq = function(expected_type, expected_val, str, ...) | ||||||
|  |       nvim_command(('let g:__val = msgpack#eval(\'%s\', %s)'):format(str:gsub( | ||||||
|  |           '\'', '\'\''), select(1, ...) or '{}')) | ||||||
|  |       eq(expected_type, nvim_eval('msgpack#type(g:__val)')) | ||||||
|  |       local expected_val_full = expected_val | ||||||
|  |       if (not (({float=true, integer=true})[expected_type] | ||||||
|  |               and type(expected_val) ~= 'table') | ||||||
|  |           and expected_type ~= 'array') then | ||||||
|  |         expected_val_full = {_TYPE={}, _VAL=expected_val_full} | ||||||
|  |       end | ||||||
|  |       if expected_val_full == expected_val_full then | ||||||
|  |         eq(expected_val_full, nvim_eval('g:__val')) | ||||||
|  |       else | ||||||
|  |         eq(tostring(expected_val_full), tostring(nvim_eval('g:__val'))) | ||||||
|  |       end | ||||||
|  |       nvim_command('unlet g:__val') | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     it('correctly loads binary strings', function() | ||||||
|  |       eval_eq('binary', {'abcdef'}, '"abcdef"') | ||||||
|  |       eval_eq('binary', {'abc', 'def'}, '"abc\\ndef"') | ||||||
|  |       eval_eq('binary', {'abc\ndef'}, '"abc\\0def"') | ||||||
|  |       eval_eq('binary', {'\nabc\ndef\n'}, '"\\0abc\\0def\\0"') | ||||||
|  |       eval_eq('binary', {'abc\n\n\ndef'}, '"abc\\0\\0\\0def"') | ||||||
|  |       eval_eq('binary', {'abc\n', '\ndef'}, '"abc\\0\\n\\0def"') | ||||||
|  |       eval_eq('binary', {'abc', '', '', 'def'}, '"abc\\n\\n\\ndef"') | ||||||
|  |       eval_eq('binary', {'abc', '', '', 'def', ''}, '"abc\\n\\n\\ndef\\n"') | ||||||
|  |       eval_eq('binary', {'', 'abc', '', '', 'def'}, '"\\nabc\\n\\n\\ndef"') | ||||||
|  |       eval_eq('binary', {''}, '""') | ||||||
|  |       eval_eq('binary', {'"'}, '"\\""') | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('correctly loads strings', function() | ||||||
|  |       eval_eq('string', {'abcdef'}, '="abcdef"') | ||||||
|  |       eval_eq('string', {'abc', 'def'}, '="abc\\ndef"') | ||||||
|  |       eval_eq('string', {'abc\ndef'}, '="abc\\0def"') | ||||||
|  |       eval_eq('string', {'\nabc\ndef\n'}, '="\\0abc\\0def\\0"') | ||||||
|  |       eval_eq('string', {'abc\n\n\ndef'}, '="abc\\0\\0\\0def"') | ||||||
|  |       eval_eq('string', {'abc\n', '\ndef'}, '="abc\\0\\n\\0def"') | ||||||
|  |       eval_eq('string', {'abc', '', '', 'def'}, '="abc\\n\\n\\ndef"') | ||||||
|  |       eval_eq('string', {'abc', '', '', 'def', ''}, '="abc\\n\\n\\ndef\\n"') | ||||||
|  |       eval_eq('string', {'', 'abc', '', '', 'def'}, '="\\nabc\\n\\n\\ndef"') | ||||||
|  |       eval_eq('string', {''}, '=""') | ||||||
|  |       eval_eq('string', {'"'}, '="\\""') | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('correctly loads ext values', function() | ||||||
|  |       eval_eq('ext', {0, {'abcdef'}}, '+(0)"abcdef"') | ||||||
|  |       eval_eq('ext', {0, {'abc', 'def'}}, '+(0)"abc\\ndef"') | ||||||
|  |       eval_eq('ext', {0, {'abc\ndef'}}, '+(0)"abc\\0def"') | ||||||
|  |       eval_eq('ext', {0, {'\nabc\ndef\n'}}, '+(0)"\\0abc\\0def\\0"') | ||||||
|  |       eval_eq('ext', {0, {'abc\n\n\ndef'}}, '+(0)"abc\\0\\0\\0def"') | ||||||
|  |       eval_eq('ext', {0, {'abc\n', '\ndef'}}, '+(0)"abc\\0\\n\\0def"') | ||||||
|  |       eval_eq('ext', {0, {'abc', '', '', 'def'}}, '+(0)"abc\\n\\n\\ndef"') | ||||||
|  |       eval_eq('ext', {0, {'abc', '', '', 'def', ''}}, | ||||||
|  |               '+(0)"abc\\n\\n\\ndef\\n"') | ||||||
|  |       eval_eq('ext', {0, {'', 'abc', '', '', 'def'}}, | ||||||
|  |               '+(0)"\\nabc\\n\\n\\ndef"') | ||||||
|  |       eval_eq('ext', {0, {''}}, '+(0)""') | ||||||
|  |       eval_eq('ext', {0, {'"'}}, '+(0)"\\""') | ||||||
|  |  | ||||||
|  |       eval_eq('ext', {-1, {'abcdef'}}, '+(-1)"abcdef"') | ||||||
|  |       eval_eq('ext', {-1, {'abc', 'def'}}, '+(-1)"abc\\ndef"') | ||||||
|  |       eval_eq('ext', {-1, {'abc\ndef'}}, '+(-1)"abc\\0def"') | ||||||
|  |       eval_eq('ext', {-1, {'\nabc\ndef\n'}}, '+(-1)"\\0abc\\0def\\0"') | ||||||
|  |       eval_eq('ext', {-1, {'abc\n\n\ndef'}}, '+(-1)"abc\\0\\0\\0def"') | ||||||
|  |       eval_eq('ext', {-1, {'abc\n', '\ndef'}}, '+(-1)"abc\\0\\n\\0def"') | ||||||
|  |       eval_eq('ext', {-1, {'abc', '', '', 'def'}}, '+(-1)"abc\\n\\n\\ndef"') | ||||||
|  |       eval_eq('ext', {-1, {'abc', '', '', 'def', ''}}, | ||||||
|  |               '+(-1)"abc\\n\\n\\ndef\\n"') | ||||||
|  |       eval_eq('ext', {-1, {'', 'abc', '', '', 'def'}}, | ||||||
|  |               '+(-1)"\\nabc\\n\\n\\ndef"') | ||||||
|  |       eval_eq('ext', {-1, {''}}, '+(-1)""') | ||||||
|  |       eval_eq('ext', {-1, {'"'}}, '+(-1)"\\""') | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('correctly loads floats', function() | ||||||
|  |       eval_eq('float', inf, 'inf') | ||||||
|  |       eval_eq('float', minus_inf, '-inf') | ||||||
|  |       eval_eq('float', nan, 'nan') | ||||||
|  |       eval_eq('float', minus_nan, '-nan') | ||||||
|  |       eval_eq('float', 1.0e10, '1.0e10') | ||||||
|  |       eval_eq('float', 1.0e10, '1.0e+10') | ||||||
|  |       eval_eq('float', -1.0e10, '-1.0e+10') | ||||||
|  |       eval_eq('float', 1.0, '1.0') | ||||||
|  |       eval_eq('float', -1.0, '-1.0') | ||||||
|  |       eval_eq('float', 1.0e-10, '1.0e-10') | ||||||
|  |       eval_eq('float', -1.0e-10, '-1.0e-10') | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('correctly loads integers', function() | ||||||
|  |       eval_eq('integer', 10, '10') | ||||||
|  |       eval_eq('integer', -10, '-10') | ||||||
|  |       eval_eq('integer', { 1, 0,  610839793, 448585456}, ' 0x123456789ABCDEF0') | ||||||
|  |       eval_eq('integer', {-1, 0,  610839793, 448585456}, '-0x123456789ABCDEF0') | ||||||
|  |       eval_eq('integer', { 1, 3, 1684581617, 448585456}, ' 0xF23456789ABCDEF0') | ||||||
|  |       eval_eq('integer', {-1, 1, 1684581617, 448585456}, '-0x723456789ABCDEF0') | ||||||
|  |       eval_eq('integer', { 1, 0, 0, 0x100}, '0x100') | ||||||
|  |       eval_eq('integer', {-1, 0, 0, 0x100}, '-0x100') | ||||||
|  |  | ||||||
|  |       eval_eq('integer', ('a'):byte(), '\'a\'') | ||||||
|  |       eval_eq('integer', 0xAB, '\'«\'') | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('correctly loads constants', function() | ||||||
|  |       eval_eq('boolean', 1, 'TRUE') | ||||||
|  |       eval_eq('boolean', 0, 'FALSE') | ||||||
|  |       eval_eq('nil', 0, 'NIL') | ||||||
|  |       eval_eq('nil', 0, 'NIL', '{"NIL": 1, "nan": 2, "T": 3}') | ||||||
|  |       eval_eq('float', nan, 'nan', | ||||||
|  |               '{"NIL": "1", "nan": "2", "T": "3"}') | ||||||
|  |       eval_eq('integer', 3, 'T', '{"NIL": "1", "nan": "2", "T": "3"}') | ||||||
|  |       eval_eq('integer', {1, 0, 0, 0}, 'T', | ||||||
|  |               ('{"NIL": "1", "nan": "2", "T": \'%s\'}'):format( | ||||||
|  |                   sp('integer', '[1, 0, 0, 0]'))) | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('correctly loads maps', function() | ||||||
|  |       eval_eq('map', {}, '{}') | ||||||
|  |       eval_eq('map', {{{_TYPE={}, _VAL={{1, 2}}}, {_TYPE={}, _VAL={{3, 4}}}}}, | ||||||
|  |               '{{1: 2}: {3: 4}}') | ||||||
|  |       eval_eq('map', {{{_TYPE={}, _VAL={{1, 2}}}, {_TYPE={}, _VAL={{3, 4}}}}, | ||||||
|  |                       {1, 2}}, | ||||||
|  |               '{{1: 2}: {3: 4}, 1: 2}') | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('correctly loads arrays', function() | ||||||
|  |       eval_eq('array', {}, '[]') | ||||||
|  |       eval_eq('array', {1}, '[1]') | ||||||
|  |       eval_eq('array', {{_TYPE={}, _VAL=1}}, '[TRUE]') | ||||||
|  |       eval_eq('array', {{{_TYPE={}, _VAL={{1, 2}}}}, {_TYPE={}, _VAL={{3, 4}}}}, | ||||||
|  |               '[[{1: 2}], {3: 4}]') | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     it('errors out when needed', function() | ||||||
|  |       eq('empty:Parsed string is empty', | ||||||
|  |          exc_exec('call msgpack#eval("", {})')) | ||||||
|  |       eq('unknown:Invalid non-space character: ^', | ||||||
|  |          exc_exec('call msgpack#eval("^", {})')) | ||||||
|  |       eq('char-invalid:Invalid integer character literal format: \'\'', | ||||||
|  |          exc_exec('call msgpack#eval("\'\'", {})')) | ||||||
|  |       eq('char-invalid:Invalid integer character literal format: \'ab\'', | ||||||
|  |          exc_exec('call msgpack#eval("\'ab\'", {})')) | ||||||
|  |       eq('char-invalid:Invalid integer character literal format: \'', | ||||||
|  |          exc_exec('call msgpack#eval("\'", {})')) | ||||||
|  |       eq('"-invalid:Invalid string: "', | ||||||
|  |          exc_exec('call msgpack#eval("\\"", {})')) | ||||||
|  |       eq('"-invalid:Invalid string: ="', | ||||||
|  |          exc_exec('call msgpack#eval("=\\"", {})')) | ||||||
|  |       eq('"-invalid:Invalid string: +(0)"', | ||||||
|  |          exc_exec('call msgpack#eval("+(0)\\"", {})')) | ||||||
|  |       eq('0.-nodigits:Decimal dot must be followed by digit(s): .e1', | ||||||
|  |          exc_exec('call msgpack#eval("0.e1", {})')) | ||||||
|  |       eq('0x-long:Must have at most 16 hex digits: FEDCBA98765432100', | ||||||
|  |          exc_exec('call msgpack#eval("0xFEDCBA98765432100", {})')) | ||||||
|  |       eq('0x-empty:Must have number after 0x: ', | ||||||
|  |          exc_exec('call msgpack#eval("0x", {})')) | ||||||
|  |       eq('name-unknown:Unknown name FOO: FOO', | ||||||
|  |          exc_exec('call msgpack#eval("FOO", {})')) | ||||||
|  |     end) | ||||||
|  |   end) | ||||||
|  | end) | ||||||
							
								
								
									
										2833
									
								
								test/functional/plugin/shada_spec.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2833
									
								
								test/functional/plugin/shada_spec.lua
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user
	 Felipe Morales
					Felipe Morales