The R Project SVN R

Rev

Rev 86871 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
41020 ripley 1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  file rt_complete.c
86871 kalibera 4
 *  Copyright (C) 2007-2024 The R Core Team.
41020 ripley 5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
42300 ripley 17
 *  along with this program; if not, a copy is available at
68956 ripley 18
 *  https://www.R-project.org/Licenses/
41020 ripley 19
 */
20
 
21
 
22
#ifdef HAVE_CONFIG_H
23
#include <config.h>
24
#endif
25
 
26
#include <getline/getline.h>
42431 ripley 27
#include <string.h>
28
#include <stdlib.h> /* for getenv */
29
 
42572 ripley 30
#ifndef min
31
/* in stdlib.h in Win64 headers */
32
# define min(a, b) (a < b ? a : b)
33
#endif
41020 ripley 34
 
87175 kalibera 35
#include <Defn.h>
41020 ripley 36
#include <Rinternals.h>
37
#include <R_ext/Parse.h>
38
 
43238 ripley 39
static int completion_available = -1;
41020 ripley 40
 
43117 ripley 41
static int gl_tab(char *buf, int offset, int *loc)
42
/* default tab handler, acts like tabstops every 8 cols */
43
{
44
    int i, count, len;
45
 
46
    len = strlen(buf);
47
    count = 8 - (offset + *loc) % 8;
48
    for (i=len; i >= *loc; i--)
45070 ripley 49
	buf[i+count] = buf[i];
43117 ripley 50
    for (i=0; i < count; i++)
45070 ripley 51
	buf[*loc+i] = ' ';
43117 ripley 52
    i = *loc;
53
    *loc = i + count;
54
    return i;
55
}
56
 
41020 ripley 57
static int rt_completion(char *buf, int offset, int *loc)
58
{
59
    int i, alen, cursor_position = *loc;
60
    char *partial_line = buf;
41771 ripley 61
    const char *additional_text;
41020 ripley 62
    SEXP cmdSexp, cmdexpr, ans = R_NilValue;
63
    ParseStatus status;
82340 kalibera 64
    const void *vmax = NULL;
41020 ripley 65
 
43238 ripley 66
    if(!completion_available) return gl_tab(buf, offset, loc);
45070 ripley 67
 
43238 ripley 68
    if(completion_available < 0) {
41029 ripley 69
	char *p = getenv("R_COMPLETION");
70
	if(p && strcmp(p, "FALSE") == 0) {
43238 ripley 71
	    completion_available = 0;
45070 ripley 72
	    return gl_tab(buf, offset, loc);
41029 ripley 73
	}
41020 ripley 74
	/* First check if namespace is loaded */
86821 luke 75
	if(R_findVarInFrame(R_NamespaceRegistry, install("utils"))
43238 ripley 76
	   != R_UnboundValue) completion_available = 1;
41020 ripley 77
	else { /* Then try to load it */
43238 ripley 78
	    char *p = "try(loadNamespace('utils'), silent=TRUE)";
41020 ripley 79
	    PROTECT(cmdSexp = mkString(p));
80
	    cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
81
	    if(status == PARSE_OK) {
82
		for(i = 0; i < length(cmdexpr); i++)
83
		    eval(VECTOR_ELT(cmdexpr, i), R_GlobalEnv);
84
	    }
85
	    UNPROTECT(2);
86821 luke 86
	    if(R_findVarInFrame(R_NamespaceRegistry, install("utils"))
43238 ripley 87
	       != R_UnboundValue) completion_available = 1;
41020 ripley 88
	    else {
43238 ripley 89
		completion_available = 0;
41020 ripley 90
		return -1; /* no change */
91
	    }
92
	}
93
    }
94
 
72455 murdoch 95
    alen = strlen(partial_line);
96
    char orig[alen + 1], pline[2*alen + 1],
97
            *pchar = pline, achar;
98
    strcpy(orig, partial_line);
99
    for (i = 0; i < alen; i++) {
100
        achar = orig[i];
101
	if (achar == '"' || achar == '\\') *pchar++ = '\\';
102
	*pchar++ = achar;
103
    }
104
    *pchar = 0;
83463 kalibera 105
    size_t plen = strlen(pline);
106
    size_t len = plen + 100; 
62583 ripley 107
    char cmd[len];
108
    snprintf(cmd, len,
83463 kalibera 109
	     "utils:::.win32consoleCompletion(\"%.*s\", %d)",
110
	     (int)plen, pline, cursor_position);
41020 ripley 111
    PROTECT(cmdSexp = mkString(cmd));
112
    cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
113
    if (status != PARSE_OK) {
114
	UNPROTECT(2);
115
	/* Uncomment next line to debug */
116
	/* Rprintf("failed: %s \n", cmd); */
117
	/* otherwise pretend that nothing happened and return */
118
	return -1; /* no change */
119
    }
42433 ripley 120
    /* Loop is needed here as EXPRSEXP will be of length > 1 */
41020 ripley 121
    for(i = 0; i < length(cmdexpr); i++)
122
	ans = eval(VECTOR_ELT(cmdexpr, i), R_GlobalEnv);
123
    UNPROTECT(2);
82340 kalibera 124
    PROTECT(ans);
45070 ripley 125
 
41020 ripley 126
    /* ans has the form list(addition, possible), where 'addition' is
127
       unique additional text if any, and 'possible' is a character
128
       vector holding possible completions if any (already formatted
129
       for linewise printing in the current implementation).  If
130
       'possible' has any content, we want to print those (or show in
131
       status bar or whatever).  Otherwise add the 'additional' text
132
       at the cursor */
133
 
134
#define ADDITION 0
135
#define POSSIBLE 1
136
 
82340 kalibera 137
    vmax = vmaxget();
41020 ripley 138
    alen = length(VECTOR_ELT(ans, POSSIBLE));
139
    if (alen) {
140
	int max_show = 10;
141
	printf("\n"); /* finish current line */
142
	for (i = 0; i < min(alen, max_show); i++) {
82340 kalibera 143
	    printf("%s\n", translateChar(STRING_ELT(VECTOR_ELT(ans, POSSIBLE), i)));
41020 ripley 144
	}
145
	if (alen > max_show)
146
	    printf("\n[...truncated]\n");
147
	cursor_position = -2; /* Need to redisplay whole line */
148
    }
82340 kalibera 149
    additional_text = translateChar(STRING_ELT( VECTOR_ELT(ans, ADDITION), 0 ));
41020 ripley 150
    alen = strlen(additional_text);
151
    if (alen) {
152
	int cp = *loc;
41070 ripley 153
	memcpy(buf+cp, additional_text, alen+1);
41020 ripley 154
	*loc = cp + alen;
155
    }
82340 kalibera 156
    vmaxset(vmax);
157
    UNPROTECT(1); /* ans */
41020 ripley 158
    return cursor_position;
159
}
160
 
161
 
162
void R_gl_tab_set(void)
163
{
164
    gl_tab_hook = rt_completion;
165
}