  Provide a new list_multisel_dialog() function

    Avaliable as a patch:

    http://sourceforge.net/tracker/index.php?func=detail&aid=988172&group_id=11005&atid=311005
	    [ 988172 ] Provide a new list_multisel_dialog() function
	    ListMultiSel.diff	2004-07-09 12:00

  The new builtin macro function, list_multisel_dialog(), acts as a complement
  to the current list_dialog() function. It works in exactly the same way,
  except that the user can choose more than one of the presented lines in the
  list. These lines are returned to the user as a single string, with the lines
  separated by the newline "\n" character. (Note that there is no "\n" at the
  end of the last of the selected lines returned in the string.)

  The same pseudovariable, $list_dialog_button, is used by both functions to
  return the number of the dialog button pressed.

  I decided to use a single string return value rather than an array value for
  two reasons. Firstly, the input and output are in the same format. Second,
  doing things this way avoids having to deal with indices to an array, and
  conversion to an array can already be performed very readily using split. It
  was also easier to implement this way.

  As part of this patch I increased the list's maximum display length on dialog
  creation from 10 to 25. (I spend a lot of time simply resizing such dialogs
  since 10 lines is usually too small a window for me.) Ideally, this should be
  configurable (through a non-saved X resource would be sufficient).

	    ListMultiSel2.diff 2004-07-27 19:03

  Corrected a bug whereby the string result had a badly set length (the
  character count was too great by 1).

diff -ur nedit_official nedit_mod
diff -ur nedit_official/doc/help.etx nedit_mod/doc/help.etx
--- nedit_official/doc/help.etx	2007-10-18 18:37:55.000000000 +0200
+++ nedit_mod/doc/help.etx	2007-10-18 19:24:40.067427200 +0200
@@ -2608,12 +2608,25 @@
   fixed text describing the list. The second string provides the list data:
   this is a text string in which list entries are separated by newline
   characters. Additional optional arguments represent labels for
-  buttons to appear along the bottom of the dialog. Returns the line of text
-  selected by the user as the function value (without any newline separator) or
-  the empty string if none was selected, and number of the button pressed (the
-  first button is number 1), in $list_dialog_button. If the user closes the
-  dialog via the window close box, the function returns the empty string, and
-  $list_dialog_button returns 0.
+  buttons to appear along the bottom of the dialog. Returns a string holding the
+  single line of text selected by the user (without any newline separator) or
+  the empty string if none was selected, and the number of the button pressed
+  (the first button is number 1), in $list_dialog_button. If the user closes the
+  dialog via the window close box or by the escape key, the function returns the
+  empty string, and $list_dialog_button returns 0.
+
+**list_multisel_dialog( message, text, btn_1_label, btn_2_label, ... )**  
+  Pop up a dialog for prompting the user to choose a line from the given text
+  string. The first argument is a message string to be used as a title for the
+  fixed text describing the list. The second string provides the list data:
+  this is a text string in which list entries are separated by newline
+  characters. Additional optional arguments represent labels for buttons to
+  appear along the bottom of the dialog. Returns a string holding all lines of
+  text selected by the user (separated by newline characters) or the empty
+  string if none was selected, and the number of the button pressed (the first
+  button is number 1), in $list_dialog_button. If the user closes the dialog via
+  the window close box or by the escape key, the function returns the empty
+  string, and $list_dialog_button returns 0.
 
 **max( n1, n2, ... )**
   Returns the maximum value of all of its arguments
diff -ur nedit_official/source/macro.c nedit_mod/source/macro.c
--- nedit_official/source/macro.c	2007-10-18 18:37:56.000000000 +0200
+++ nedit_mod/source/macro.c	2007-10-18 19:24:40.087456000 +0200
@@ -238,8 +238,12 @@
 static int killCalltipMS(WindowInfo *window, DataValue *argList, int nArgs,
        DataValue *result, char **errMsg);
 /* T Balinski */
+static int listDialogBase(WindowInfo *window, DataValue *argList, int nArgs,
+      DataValue *result, char **errMsg, Boolean isMultiLine);
 static int listDialogMS(WindowInfo *window, DataValue *argList, int nArgs,
 	DataValue *result, char **errMsg);
+static int listMultiselDialogMS(WindowInfo *window, DataValue *argList,
+        int nArgs, DataValue *result, char **errMsg);
 static void listDialogBtnCB(Widget w, XtPointer clientData,
 	XtPointer callData);
 static void listDialogCloseCB(Widget w, XtPointer clientData,
@@ -414,7 +418,7 @@
         writeFileMS, appendFileMS, beepMS, getSelectionMS, validNumberMS,
         replaceInStringMS, selectMS, selectRectangleMS, focusWindowMS,
         shellCmdMS, stringToClipboardMS, clipboardToStringMS, toupperMS,
-        tolowerMS, listDialogMS, getenvMS,
+        tolowerMS, listDialogMS, listMultiselDialogMS, getenvMS,
         stringCompareMS, splitMS, calltipMS, killCalltipMS,
 /* DISABLED for 5.4        setBacklightStringMS,*/
         rangesetCreateMS, rangesetDestroyMS,
@@ -433,7 +437,7 @@
         "write_file", "append_file", "beep", "get_selection", "valid_number",
         "replace_in_string", "select", "select_rectangle", "focus_window",
         "shell_command", "string_to_clipboard", "clipboard_to_string",
-        "toupper", "tolower", "list_dialog", "getenv",
+        "toupper", "tolower", "list_dialog", "list_multisel_dialog", "getenv",
         "string_compare", "split", "calltip", "kill_calltip",
 /* DISABLED for 5.4        "set_backlight_string", */
         "rangeset_create", "rangeset_destroy",
@@ -3480,8 +3484,8 @@
 }
 
 /* T Balinski */
-static int listDialogMS(WindowInfo *window, DataValue *argList, int nArgs,
-      DataValue *result, char **errMsg)
+static int listDialogBase(WindowInfo *window, DataValue *argList, int nArgs,
+      DataValue *result, char **errMsg, Boolean isMultiLine)
 {
     macroCmdInfo *cmdData;
     char stringStorage[TYPE_INT_STR_SIZE(int)];
@@ -3628,7 +3632,7 @@
     XtSetArg(al[ac], XmNlistLabelString, s1=MKSTRING(message)); ac++;
     XtSetArg(al[ac], XmNlistItems, test_strings); ac++;
     XtSetArg(al[ac], XmNlistItemCount, nlines); ac++;
-    XtSetArg(al[ac], XmNlistVisibleItemCount, (nlines > 10) ? 10 : nlines); ac++;
+    XtSetArg(al[ac], XmNlistVisibleItemCount, (nlines > 25) ? 25 : nlines); ac++;
     XtSetArg(al[ac], XmNokLabelString, s2=XmStringCreateSimple(btnLabel)); ac++;
     dialog = CreateSelectionDialog(window->shell, "macroListDialog", al, ac);
     if (2 == nArgs)
@@ -3654,7 +3658,8 @@
 
     /* modify the list */
     XtVaSetValues(XmSelectionBoxGetChild(dialog, XmDIALOG_LIST),
-                XmNselectionPolicy, XmSINGLE_SELECT,
+                XmNselectionPolicy,
+                            isMultiLine ? XmMULTIPLE_SELECT : XmSINGLE_SELECT,
                 XmNuserData, (XtPointer)text_lines, NULL);
 
     /* Unmanage unneeded widgets */
@@ -3703,6 +3708,18 @@
     return True;
 }
 
+static int listDialogMS(WindowInfo *window, DataValue *argList, int nArgs,
+      DataValue *result, char **errMsg)
+{
+    return listDialogBase(window, argList, nArgs, result, errMsg, False);
+}
+
+static int listMultiselDialogMS(WindowInfo *window, DataValue *argList,
+      int nArgs, DataValue *result, char **errMsg)
+{
+    return listDialogBase(window, argList, nArgs, result, errMsg, True);
+}
+
 static void listDialogBtnCB(Widget w, XtPointer clientData,
       XtPointer callData)
 {
@@ -3714,6 +3731,8 @@
     char **text_lines;
     int btnNum;
     int n_sel, *seltable, sel_index = 0;
+    int selPolicy;
+    Boolean isMultiLine;
     Widget theList;
     size_t length;
 
@@ -3725,21 +3744,36 @@
     /* Return the string selected in the selection list area */
     XtVaGetValues(theList, XmNuserData, &text_lines, NULL);
     if (!XmListGetSelectedPos(theList, &seltable, &n_sel)) {
-      n_sel = 0;
-    }
-    else {
-      sel_index = seltable[0] - 1;
-      XtFree((XtPointer)seltable);
+      n_sel = -1;
     }
 
-    if (!n_sel) {
+    if (n_sel < 0) {
       text = PERM_ALLOC_STR("");
       length = 0;
+      n_sel = 0;
     }
     else {
-      length = strlen((char *)text_lines[sel_index]);
-      text = AllocString(length + 1);
-      strcpy(text, text_lines[sel_index]);
+        /* count up the total size of the result */
+        int i;
+        size_t len;
+        char *cp;
+        length = 0;
+        for (i = 0; i < n_sel; i++) {
+            sel_index = seltable[i] - 1;
+            length += strlen((char *)text_lines[sel_index]) + 1;
+        }
+        /* allocate result */
+        cp = text = AllocString(length);
+        /* and copy strings, separated by '\n' */
+        for (i = 0; i < n_sel; i++) {
+            sel_index = seltable[i] - 1;
+            len = strlen((char *)text_lines[sel_index]);
+            strcpy(cp, text_lines[sel_index]);
+            cp += len;
+            *cp++ = '\n';
+        }
+        text[--length] = '\0';
+        XtFree((XtPointer)seltable);
     }
 
     /* don't need text_lines anymore: free it */
