patch 7.4.1560
Problem:    Dict options with a dash are more difficult to use.
Solution:   Use an underscore, so that dict.err_io can be used.
diff --git a/src/channel.c b/src/channel.c
index 81823bc..e66be18 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -3148,7 +3148,7 @@
 		if (handle_mode(item, opt, &opt->jo_mode, JO_MODE) == FAIL)
 		    return FAIL;
 	    }
-	    else if (STRCMP(hi->hi_key, "in-mode") == 0)
+	    else if (STRCMP(hi->hi_key, "in_mode") == 0)
 	    {
 		if (!(supported & JO_IN_MODE))
 		    break;
@@ -3156,7 +3156,7 @@
 								      == FAIL)
 		    return FAIL;
 	    }
-	    else if (STRCMP(hi->hi_key, "out-mode") == 0)
+	    else if (STRCMP(hi->hi_key, "out_mode") == 0)
 	    {
 		if (!(supported & JO_OUT_MODE))
 		    break;
@@ -3164,7 +3164,7 @@
 								      == FAIL)
 		    return FAIL;
 	    }
-	    else if (STRCMP(hi->hi_key, "err-mode") == 0)
+	    else if (STRCMP(hi->hi_key, "err_mode") == 0)
 	    {
 		if (!(supported & JO_ERR_MODE))
 		    break;
@@ -3172,18 +3172,18 @@
 								      == FAIL)
 		    return FAIL;
 	    }
-	    else if (STRCMP(hi->hi_key, "in-io") == 0
-		    || STRCMP(hi->hi_key, "out-io") == 0
-		    || STRCMP(hi->hi_key, "err-io") == 0)
+	    else if (STRCMP(hi->hi_key, "in_io") == 0
+		    || STRCMP(hi->hi_key, "out_io") == 0
+		    || STRCMP(hi->hi_key, "err_io") == 0)
 	    {
 		if (!(supported & JO_OUT_IO))
 		    break;
 		if (handle_io(item, part_from_char(*hi->hi_key), opt) == FAIL)
 		    return FAIL;
 	    }
-	    else if (STRCMP(hi->hi_key, "in-name") == 0
-		    || STRCMP(hi->hi_key, "out-name") == 0
-		    || STRCMP(hi->hi_key, "err-name") == 0)
+	    else if (STRCMP(hi->hi_key, "in_name") == 0
+		    || STRCMP(hi->hi_key, "out_name") == 0
+		    || STRCMP(hi->hi_key, "err_name") == 0)
 	    {
 		part = part_from_char(*hi->hi_key);
 
@@ -3193,9 +3193,9 @@
 		opt->jo_io_name[part] =
 		       get_tv_string_buf_chk(item, opt->jo_io_name_buf[part]);
 	    }
-	    else if (STRCMP(hi->hi_key, "in-buf") == 0
-		    || STRCMP(hi->hi_key, "out-buf") == 0
-		    || STRCMP(hi->hi_key, "err-buf") == 0)
+	    else if (STRCMP(hi->hi_key, "in_buf") == 0
+		    || STRCMP(hi->hi_key, "out_buf") == 0
+		    || STRCMP(hi->hi_key, "err_buf") == 0)
 	    {
 		part = part_from_char(*hi->hi_key);
 
@@ -3214,8 +3214,8 @@
 		    return FAIL;
 		}
 	    }
-	    else if (STRCMP(hi->hi_key, "in-top") == 0
-		    || STRCMP(hi->hi_key, "in-bot") == 0)
+	    else if (STRCMP(hi->hi_key, "in_top") == 0
+		    || STRCMP(hi->hi_key, "in_bot") == 0)
 	    {
 		linenr_T *lp;
 
@@ -3262,7 +3262,7 @@
 		    return FAIL;
 		}
 	    }
-	    else if (STRCMP(hi->hi_key, "out-cb") == 0)
+	    else if (STRCMP(hi->hi_key, "out_cb") == 0)
 	    {
 		if (!(supported & JO_OUT_CALLBACK))
 		    break;
@@ -3270,11 +3270,11 @@
 		opt->jo_out_cb = get_callback(item, &opt->jo_out_partial);
 		if (opt->jo_out_cb == NULL)
 		{
-		    EMSG2(_(e_invarg2), "out-cb");
+		    EMSG2(_(e_invarg2), "out_cb");
 		    return FAIL;
 		}
 	    }
-	    else if (STRCMP(hi->hi_key, "err-cb") == 0)
+	    else if (STRCMP(hi->hi_key, "err_cb") == 0)
 	    {
 		if (!(supported & JO_ERR_CALLBACK))
 		    break;
@@ -3282,11 +3282,11 @@
 		opt->jo_err_cb = get_callback(item, &opt->jo_err_partial);
 		if (opt->jo_err_cb == NULL)
 		{
-		    EMSG2(_(e_invarg2), "err-cb");
+		    EMSG2(_(e_invarg2), "err_cb");
 		    return FAIL;
 		}
 	    }
-	    else if (STRCMP(hi->hi_key, "close-cb") == 0)
+	    else if (STRCMP(hi->hi_key, "close_cb") == 0)
 	    {
 		if (!(supported & JO_CLOSE_CALLBACK))
 		    break;
@@ -3294,7 +3294,7 @@
 		opt->jo_close_cb = get_callback(item, &opt->jo_close_partial);
 		if (opt->jo_close_cb == NULL)
 		{
-		    EMSG2(_(e_invarg2), "close-cb");
+		    EMSG2(_(e_invarg2), "close_cb");
 		    return FAIL;
 		}
 	    }
@@ -3312,14 +3312,14 @@
 		opt->jo_set |= JO_TIMEOUT;
 		opt->jo_timeout = get_tv_number(item);
 	    }
-	    else if (STRCMP(hi->hi_key, "out-timeout") == 0)
+	    else if (STRCMP(hi->hi_key, "out_timeout") == 0)
 	    {
 		if (!(supported & JO_OUT_TIMEOUT))
 		    break;
 		opt->jo_set |= JO_OUT_TIMEOUT;
 		opt->jo_out_timeout = get_tv_number(item);
 	    }
-	    else if (STRCMP(hi->hi_key, "err-timeout") == 0)
+	    else if (STRCMP(hi->hi_key, "err_timeout") == 0)
 	    {
 		if (!(supported & JO_ERR_TIMEOUT))
 		    break;
@@ -3360,7 +3360,7 @@
 		    return FAIL;
 		}
 	    }
-	    else if (STRCMP(hi->hi_key, "exit-cb") == 0)
+	    else if (STRCMP(hi->hi_key, "exit_cb") == 0)
 	    {
 		if (!(supported & JO_EXIT_CB))
 		    break;
@@ -3375,7 +3375,7 @@
 						       item, opt->jo_ecb_buf);
 		if (opt->jo_exit_cb == NULL)
 		{
-		    EMSG2(_(e_invarg2), "exit-cb");
+		    EMSG2(_(e_invarg2), "exit_cb");
 		    return FAIL;
 		}
 	    }
@@ -3546,7 +3546,7 @@
 }
 
 /*
- * Called once in a while: check if any jobs with an "exit-cb" have ended.
+ * Called once in a while: check if any jobs with an "exit_cb" have ended.
  */
     void
 job_check_ended(void)
@@ -3609,7 +3609,7 @@
 		&& (!(opt.jo_set & (JO_OUT_NAME << (part - PART_OUT)))
 		    || *opt.jo_io_name[part] == NUL))
 	{
-	    EMSG(_("E920: -io file requires -name to be set"));
+	    EMSG(_("E920: _io file requires _name to be set"));
 	    return job;
 	}
 
@@ -3626,7 +3626,7 @@
 	}
 	else if (!(opt.jo_set & JO_IN_NAME))
 	{
-	    EMSG(_("E915: in-io buffer requires in-buf or in-name to be set"));
+	    EMSG(_("E915: in_io buffer requires in_buf or in_name to be set"));
 	}
 	else
 	    buf = buflist_find_by_name(opt.jo_io_name[PART_IN], FALSE);
@@ -3837,7 +3837,7 @@
     dict_add_nr_str(dict, "process", nr, NULL);
 
     dict_add_nr_str(dict, "exitval", job->jv_exitval, NULL);
-    dict_add_nr_str(dict, "exit-cb", 0L, job->jv_exit_cb);
+    dict_add_nr_str(dict, "exit_cb", 0L, job->jv_exit_cb);
     dict_add_nr_str(dict, "stoponexit", 0L, job->jv_stoponexit);
 }
 
diff --git a/src/structs.h b/src/structs.h
index 04360e2..ab707d8 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1414,18 +1414,18 @@
 #define JO_PART		    0x1000	/* "part" */
 #define JO_ID		    0x2000	/* "id" */
 #define JO_STOPONEXIT	    0x4000	/* "stoponexit" */
-#define JO_EXIT_CB	    0x8000	/* "exit-cb" */
-#define JO_OUT_IO	    0x10000	/* "out-io" */
-#define JO_ERR_IO	    0x20000	/* "err-io" (JO_OUT_IO << 1) */
-#define JO_IN_IO	    0x40000	/* "in-io" (JO_OUT_IO << 2) */
-#define JO_OUT_NAME	    0x80000	/* "out-name" */
-#define JO_ERR_NAME	    0x100000	/* "err-name" (JO_OUT_NAME << 1) */
-#define JO_IN_NAME	    0x200000	/* "in-name" (JO_OUT_NAME << 2) */
-#define JO_IN_TOP	    0x400000	/* "in-top" */
-#define JO_IN_BOT	    0x800000	/* "in-bot" */
-#define JO_OUT_BUF	    0x1000000	/* "out-buf" */
-#define JO_ERR_BUF	    0x2000000	/* "err-buf" (JO_OUT_BUF << 1) */
-#define JO_IN_BUF	    0x4000000	/* "in-buf" (JO_OUT_BUF << 2) */
+#define JO_EXIT_CB	    0x8000	/* "exit_cb" */
+#define JO_OUT_IO	    0x10000	/* "out_io" */
+#define JO_ERR_IO	    0x20000	/* "err_io" (JO_OUT_IO << 1) */
+#define JO_IN_IO	    0x40000	/* "in_io" (JO_OUT_IO << 2) */
+#define JO_OUT_NAME	    0x80000	/* "out_name" */
+#define JO_ERR_NAME	    0x100000	/* "err_name" (JO_OUT_NAME << 1) */
+#define JO_IN_NAME	    0x200000	/* "in_name" (JO_OUT_NAME << 2) */
+#define JO_IN_TOP	    0x400000	/* "in_top" */
+#define JO_IN_BOT	    0x800000	/* "in_bot" */
+#define JO_OUT_BUF	    0x1000000	/* "out_buf" */
+#define JO_ERR_BUF	    0x2000000	/* "err_buf" (JO_OUT_BUF << 1) */
+#define JO_IN_BUF	    0x4000000	/* "in_buf" (JO_OUT_BUF << 2) */
 #define JO_CHANNEL	    0x8000000	/* "channel" */
 #define JO_ALL		    0xfffffff
 
diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim
index c50c1df..6d38bff 100644
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -519,7 +519,7 @@
   endif
   call ch_logfile('Xlog')
   call ch_log('Test_nl_err_to_out_pipe()')
-  let job = job_start(s:python . " test_channel_pipe.py", {'err-io': 'out'})
+  let job = job_start(s:python . " test_channel_pipe.py", {'err_io': 'out'})
   call assert_equal("run", job_status(job))
   try
     let handle = job_getchannel(job)
@@ -566,7 +566,7 @@
   call ch_log('Test_nl_read_file()')
   call writefile(['echo something', 'echoerr wrong', 'double this'], 'Xinput')
   let job = job_start(s:python . " test_channel_pipe.py",
-	\ {'in-io': 'file', 'in-name': 'Xinput'})
+	\ {'in_io': 'file', 'in_name': 'Xinput'})
   call assert_equal("run", job_status(job))
   try
     let handle = job_getchannel(job)
@@ -586,7 +586,7 @@
   endif
   call ch_log('Test_nl_write_out_file()')
   let job = job_start(s:python . " test_channel_pipe.py",
-	\ {'out-io': 'file', 'out-name': 'Xoutput'})
+	\ {'out_io': 'file', 'out_name': 'Xoutput'})
   call assert_equal("run", job_status(job))
   try
     let handle = job_getchannel(job)
@@ -607,7 +607,7 @@
   endif
   call ch_log('Test_nl_write_err_file()')
   let job = job_start(s:python . " test_channel_pipe.py",
-	\ {'err-io': 'file', 'err-name': 'Xoutput'})
+	\ {'err_io': 'file', 'err_name': 'Xoutput'})
   call assert_equal("run", job_status(job))
   try
     let handle = job_getchannel(job)
@@ -628,7 +628,7 @@
   endif
   call ch_log('Test_nl_write_both_file()')
   let job = job_start(s:python . " test_channel_pipe.py",
-	\ {'out-io': 'file', 'out-name': 'Xoutput', 'err-io': 'out'})
+	\ {'out_io': 'file', 'out_name': 'Xoutput', 'err_io': 'out'})
   call assert_equal("run", job_status(job))
   try
     let handle = job_getchannel(job)
@@ -649,13 +649,13 @@
     return
   endif
   call ch_log('Test_pipe_to_buffer()')
-  let options = {'out-io': 'buffer'}
+  let options = {'out_io': 'buffer'}
   if a:use_name
-    let options['out-name'] = 'pipe-output'
+    let options['out_name'] = 'pipe-output'
     let firstline = 'Reading from channel output...'
   else
     sp pipe-output
-    let options['out-buf'] = bufnr('%')
+    let options['out_buf'] = bufnr('%')
     quit
     let firstline = ''
   endif
@@ -689,13 +689,13 @@
     return
   endif
   call ch_log('Test_pipe_err_to_buffer()')
-  let options = {'err-io': 'buffer'}
+  let options = {'err_io': 'buffer'}
   if a:use_name
-    let options['err-name'] = 'pipe-err'
+    let options['err_name'] = 'pipe-err'
     let firstline = 'Reading from channel error...'
   else
     sp pipe-err
-    let options['err-buf'] = bufnr('%')
+    let options['err_buf'] = bufnr('%')
     quit
     let firstline = ''
   endif
@@ -730,7 +730,7 @@
   endif
   call ch_log('Test_pipe_both_to_buffer()')
   let job = job_start(s:python . " test_channel_pipe.py",
-	\ {'out-io': 'buffer', 'out-name': 'pipe-err', 'err-io': 'out'})
+	\ {'out_io': 'buffer', 'out_name': 'pipe-err', 'err_io': 'out'})
   call assert_equal("run", job_status(job))
   try
     let handle = job_getchannel(job)
@@ -756,11 +756,11 @@
 
   sp pipe-input
   call setline(1, ['echo one', 'echo two', 'echo three'])
-  let options = {'in-io': 'buffer'}
+  let options = {'in_io': 'buffer'}
   if a:use_name
-    let options['in-name'] = 'pipe-input'
+    let options['in_name'] = 'pipe-input'
   else
-    let options['in-buf'] = bufnr('%')
+    let options['in_buf'] = bufnr('%')
   endif
 
   let job = job_start(s:python . " test_channel_pipe.py", options)
@@ -790,7 +790,7 @@
   endif
   call ch_log('Test_pipe_to_nameless_buffer()')
   let job = job_start(s:python . " test_channel_pipe.py",
-	\ {'out-io': 'buffer'})
+	\ {'out_io': 'buffer'})
   call assert_equal("run", job_status(job))
   try
     let handle = job_getchannel(job)
@@ -811,7 +811,7 @@
   endif
   call ch_log('Test_pipe_to_buffer_json()')
   let job = job_start(s:python . " test_channel_pipe.py",
-	\ {'out-io': 'buffer', 'out-mode': 'json'})
+	\ {'out_io': 'buffer', 'out_mode': 'json'})
   call assert_equal("run", job_status(job))
   try
     let handle = job_getchannel(job)
@@ -849,8 +849,8 @@
   set buftype=nofile
 
   let job = job_start(s:python . " test_channel_pipe.py",
-	\ {'in-io': 'buffer', 'in-name': 'pipe-input', 'in-top': 0,
-	\  'out-io': 'buffer', 'out-name': 'pipe-output'})
+	\ {'in_io': 'buffer', 'in_name': 'pipe-input', 'in_top': 0,
+	\  'out_io': 'buffer', 'out_name': 'pipe-output'})
   call assert_equal("run", job_status(job))
   try
     exe "normal Gaecho hello\<CR>"
@@ -884,8 +884,8 @@
   set buftype=nofile
 
   let job = job_start(s:python . " test_channel_pipe.py",
-	\ {'in-io': 'buffer', 'in-name': 'pipe-io', 'in-top': 0,
-	\  'out-io': 'buffer', 'out-name': 'pipe-io'})
+	\ {'in_io': 'buffer', 'in_name': 'pipe-io', 'in_top': 0,
+	\  'out_io': 'buffer', 'out_name': 'pipe-io'})
   call assert_equal("run", job_status(job))
   try
     exe "normal Goecho hello\<CR>"
@@ -912,7 +912,7 @@
   " We cannot check that no I/O works, we only check that the job starts
   " properly.
   let job = job_start(s:python . " test_channel_pipe.py something",
-	\ {'in-io': 'null'})
+	\ {'in_io': 'null'})
   call assert_equal("run", job_status(job))
   try
     call assert_equal('something', ch_read(job))
@@ -921,7 +921,7 @@
   endtry
 
   let job = job_start(s:python . " test_channel_pipe.py err-out",
-	\ {'out-io': 'null'})
+	\ {'out_io': 'null'})
   call assert_equal("run", job_status(job))
   try
     call assert_equal('err-out', ch_read(job, {"part": "err"}))
@@ -930,7 +930,7 @@
   endtry
 
   let job = job_start(s:python . " test_channel_pipe.py something",
-	\ {'err-io': 'null'})
+	\ {'err_io': 'null'})
   call assert_equal("run", job_status(job))
   try
     call assert_equal('something', ch_read(job))
@@ -939,12 +939,12 @@
   endtry
 
   let job = job_start(s:python . " test_channel_pipe.py something",
-	\ {'out-io': 'null', 'err-io': 'out'})
+	\ {'out_io': 'null', 'err_io': 'out'})
   call assert_equal("run", job_status(job))
   call job_stop(job)
 
   let job = job_start(s:python . " test_channel_pipe.py something",
-	\ {'in-io': 'null', 'out-io': 'null', 'err-io': 'null'})
+	\ {'in_io': 'null', 'out_io': 'null', 'err_io': 'null'})
   call assert_equal("run", job_status(job))
   call assert_equal('channel fail', string(job_getchannel(job)))
   call assert_equal('fail', ch_status(job))
@@ -1082,9 +1082,9 @@
 endfunc
 
 function s:test_exit_callback(port)
-  call job_setoptions(s:job, {'exit-cb': 'MyExitCb'})
+  call job_setoptions(s:job, {'exit_cb': 'MyExitCb'})
   let s:exit_job = s:job
-  call assert_equal('MyExitCb', job_info(s:job)['exit-cb'])
+  call assert_equal('MyExitCb', job_info(s:job)['exit_cb'])
 endfunc
 
 func Test_exit_callback()
@@ -1121,7 +1121,7 @@
     call assert_false(1, "Can't open channel")
     return
   endif
-  call ch_setoptions(handle, {'close-cb': 'MyCloseCb'})
+  call ch_setoptions(handle, {'close_cb': 'MyCloseCb'})
 
   call assert_equal('', ch_evalexpr(handle, 'close me'))
   call s:waitFor('"closed" == s:ch_close_ret')
diff --git a/src/version.c b/src/version.c
index eb42b32..52e2b80 100644
--- a/src/version.c
+++ b/src/version.c
@@ -744,6 +744,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1560,
+/**/
     1559,
 /**/
     1558,