1% Public functions:
2%   rline_edit_line
3%      Binding this will allow the current line to be
4%      edited in an external editor.
5%   rline_call_editor
6%      A utility function to call the editor
7%
8autoload ("new_process", "process");
9
10variable RLine_Tmp_Dir;
11private define open_tmp_file (prefix, ext)
12{
13   variable dir, dirs = ["/tmp", "$HOME"$];
14   if (__is_initialized (&RLine_Tmp_Dir))
15     dirs = [RLine_Tmp_Dir, dirs];
16
17   foreach dir (dirs)
18     {
19	variable st = stat_file (dir);
20	if (st == NULL)
21	  continue;
22	if (stat_is ("dir", st.st_mode))
23	  break;
24     }
25   then dir = "";
26
27   variable fmt = path_concat (dir, "%s%X%d.%s");
28   variable pid = getpid ();
29   variable n = 0;
30   variable file, fp;
31
32   loop (100)
33     {
34	n++;
35	file = sprintf (fmt, prefix, pid*_time(), n, ext);
36
37	variable fd = open (file, O_WRONLY|O_CREAT|O_TRUNC|O_TEXT, S_IRUSR|S_IWUSR);
38	if (fd == NULL)
39	  return;
40
41	fp = fdopen (fd, "w");
42	if (fp != NULL)
43	  return fp, fd, file;
44     }
45   throw OpenError, "Unable to open a temporary file";
46}
47
48private define get_editor ()
49{
50   variable editor = getenv("VISUAL");
51   if (editor == NULL) editor = getenv ("EDITOR");
52   if (editor == NULL) editor = "vi";
53   return editor;
54}
55
56define rline_call_editor (lines, prefix, ext)
57{
58   variable editor = get_editor ();
59   variable file, fp, fd;
60   (fp, fd, file) = open_tmp_file (prefix, ext);
61
62   EXIT_BLOCK
63     {
64	() = remove (file);
65     }
66
67   () = array_map (Int_Type, &fputs, lines+"\n", fp);
68   () = fclose (fp);
69
70   variable st = stat_file (file);
71   if (st == NULL)
72     return NULL;
73
74   variable mtime = st.st_mtime;
75
76#ifexists __rline_reset_tty
77   __rline_reset_tty ();
78#endif
79   variable p = new_process ([editor, file]).wait();
80#ifexists __rline_init_tty
81   __rline_init_tty ();
82#endif
83   rline_call ("redraw");
84
85   if ((p.exited == 0) || (p.exit_status != 0))
86     return NULL;
87
88   st = stat_file (file);
89   if ((st == NULL) || (st.st_mtime == mtime))
90     return NULL;
91
92   fp = fopen (file, "r");
93   if (fp == NULL)
94     return NULL;
95
96   lines = fgetslines (fp);
97   () = fclose (fp);
98
99   return lines;
100}
101
102define rline_edit_line ()
103{
104   variable lines = rline_get_line ();
105   lines = rline_call_editor (lines, "rline", "sl");
106   if ((lines == NULL) || (length (lines) == 0))
107     return;
108   lines = strtrim_end (lines, "\n");
109   rline_set_line (strjoin (lines, ""));
110}
111
112