The R Project SVN R

Rev

Rev 68956 | Rev 83463 | Go to most recent revision | 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
72455 murdoch 4
 *  Copyright (C) 2007-2017 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
 
35
#include <Rinternals.h>
36
#include <R_ext/Parse.h>
37
 
43238 ripley 38
static int completion_available = -1;
41020 ripley 39
 
43117 ripley 40
static int gl_tab(char *buf, int offset, int *loc)
41
/* default tab handler, acts like tabstops every 8 cols */
42
{
43
    int i, count, len;
44
 
45
    len = strlen(buf);
46
    count = 8 - (offset + *loc) % 8;
47
    for (i=len; i >= *loc; i--)
45070 ripley 48
	buf[i+count] = buf[i];
43117 ripley 49
    for (i=0; i < count; i++)
45070 ripley 50
	buf[*loc+i] = ' ';
43117 ripley 51
    i = *loc;
52
    *loc = i + count;
53
    return i;
54
}
55
 
41020 ripley 56
static int rt_completion(char *buf, int offset, int *loc)
57
{
58
    int i, alen, cursor_position = *loc;
59
    char *partial_line = buf;
41771 ripley 60
    const char *additional_text;
41020 ripley 61
    SEXP cmdSexp, cmdexpr, ans = R_NilValue;
62
    ParseStatus status;
63
 
43238 ripley 64
    if(!completion_available) return gl_tab(buf, offset, loc);
45070 ripley 65
 
43238 ripley 66
    if(completion_available < 0) {
41029 ripley 67
	char *p = getenv("R_COMPLETION");
68
	if(p && strcmp(p, "FALSE") == 0) {
43238 ripley 69
	    completion_available = 0;
45070 ripley 70
	    return gl_tab(buf, offset, loc);
41029 ripley 71
	}
41020 ripley 72
	/* First check if namespace is loaded */
43237 ripley 73
	if(findVarInFrame(R_NamespaceRegistry, install("utils"))
43238 ripley 74
	   != R_UnboundValue) completion_available = 1;
41020 ripley 75
	else { /* Then try to load it */
43238 ripley 76
	    char *p = "try(loadNamespace('utils'), silent=TRUE)";
41020 ripley 77
	    PROTECT(cmdSexp = mkString(p));
78
	    cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
79
	    if(status == PARSE_OK) {
80
		for(i = 0; i < length(cmdexpr); i++)
81
		    eval(VECTOR_ELT(cmdexpr, i), R_GlobalEnv);
82
	    }
83
	    UNPROTECT(2);
43237 ripley 84
	    if(findVarInFrame(R_NamespaceRegistry, install("utils"))
43238 ripley 85
	       != R_UnboundValue) completion_available = 1;
41020 ripley 86
	    else {
43238 ripley 87
		completion_available = 0;
41020 ripley 88
		return -1; /* no change */
89
	    }
90
	}
91
    }
92
 
72455 murdoch 93
    alen = strlen(partial_line);
94
    char orig[alen + 1], pline[2*alen + 1],
95
            *pchar = pline, achar;
96
    strcpy(orig, partial_line);
97
    for (i = 0; i < alen; i++) {
98
        achar = orig[i];
99
	if (achar == '"' || achar == '\\') *pchar++ = '\\';
100
	*pchar++ = achar;
101
    }
102
    *pchar = 0;
62583 ripley 103
    size_t len = strlen(pline) + 100; 
104
    char cmd[len];
105
    snprintf(cmd, len,
106
	     "utils:::.win32consoleCompletion(\"%s\", %d)",
107
	     pline, cursor_position);
41020 ripley 108
    PROTECT(cmdSexp = mkString(cmd));
109
    cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
110
    if (status != PARSE_OK) {
111
	UNPROTECT(2);
112
	/* Uncomment next line to debug */
113
	/* Rprintf("failed: %s \n", cmd); */
114
	/* otherwise pretend that nothing happened and return */
115
	return -1; /* no change */
116
    }
42433 ripley 117
    /* Loop is needed here as EXPRSEXP will be of length > 1 */
41020 ripley 118
    for(i = 0; i < length(cmdexpr); i++)
119
	ans = eval(VECTOR_ELT(cmdexpr, i), R_GlobalEnv);
120
    UNPROTECT(2);
45070 ripley 121
 
41020 ripley 122
    /* ans has the form list(addition, possible), where 'addition' is
123
       unique additional text if any, and 'possible' is a character
124
       vector holding possible completions if any (already formatted
125
       for linewise printing in the current implementation).  If
126
       'possible' has any content, we want to print those (or show in
127
       status bar or whatever).  Otherwise add the 'additional' text
128
       at the cursor */
129
 
130
#define ADDITION 0
131
#define POSSIBLE 1
132
 
133
    alen = length(VECTOR_ELT(ans, POSSIBLE));
134
    if (alen) {
135
	int max_show = 10;
136
	printf("\n"); /* finish current line */
137
	for (i = 0; i < min(alen, max_show); i++) {
138
	    printf("%s\n", CHAR(STRING_ELT(VECTOR_ELT(ans, POSSIBLE), i)));
139
	}
140
	if (alen > max_show)
141
	    printf("\n[...truncated]\n");
142
	cursor_position = -2; /* Need to redisplay whole line */
143
    }
144
    additional_text = CHAR(STRING_ELT( VECTOR_ELT(ans, ADDITION), 0 ));
145
    alen = strlen(additional_text);
146
    if (alen) {
147
	int cp = *loc;
41070 ripley 148
	memcpy(buf+cp, additional_text, alen+1);
41020 ripley 149
	*loc = cp + alen;
150
    }
151
    return cursor_position;
152
}
153
 
154
 
155
void R_gl_tab_set(void)
156
{
157
    gl_tab_hook = rt_completion;
158
}