The R Project SVN R

Rev

Rev 59039 | Rev 72455 | 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
62583 ripley 4
 *  Copyright (C) 2007-13 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
18
 *  http://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
 
93
    /* FIXME: need to escape quotes properly */
52804 ripley 94
    char pline[strlen(partial_line) + 1];
41020 ripley 95
    strcpy(pline, partial_line);
96
    /* poor attempt at escaping quotes that sort of works */
97
    alen = strlen(pline);
42433 ripley 98
    for (i = 0; i < alen; i++) if (pline[i] == '"') pline[i] = '\'';
41020 ripley 99
 
62583 ripley 100
    size_t len = strlen(pline) + 100; 
101
    char cmd[len];
102
    snprintf(cmd, len,
103
	     "utils:::.win32consoleCompletion(\"%s\", %d)",
104
	     pline, cursor_position);
41020 ripley 105
    PROTECT(cmdSexp = mkString(cmd));
106
    cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
107
    if (status != PARSE_OK) {
108
	UNPROTECT(2);
109
	/* Uncomment next line to debug */
110
	/* Rprintf("failed: %s \n", cmd); */
111
	/* otherwise pretend that nothing happened and return */
112
	return -1; /* no change */
113
    }
42433 ripley 114
    /* Loop is needed here as EXPRSEXP will be of length > 1 */
41020 ripley 115
    for(i = 0; i < length(cmdexpr); i++)
116
	ans = eval(VECTOR_ELT(cmdexpr, i), R_GlobalEnv);
117
    UNPROTECT(2);
45070 ripley 118
 
41020 ripley 119
    /* ans has the form list(addition, possible), where 'addition' is
120
       unique additional text if any, and 'possible' is a character
121
       vector holding possible completions if any (already formatted
122
       for linewise printing in the current implementation).  If
123
       'possible' has any content, we want to print those (or show in
124
       status bar or whatever).  Otherwise add the 'additional' text
125
       at the cursor */
126
 
127
#define ADDITION 0
128
#define POSSIBLE 1
129
 
130
    alen = length(VECTOR_ELT(ans, POSSIBLE));
131
    if (alen) {
132
	int max_show = 10;
133
	printf("\n"); /* finish current line */
134
	for (i = 0; i < min(alen, max_show); i++) {
135
	    printf("%s\n", CHAR(STRING_ELT(VECTOR_ELT(ans, POSSIBLE), i)));
136
	}
137
	if (alen > max_show)
138
	    printf("\n[...truncated]\n");
139
	cursor_position = -2; /* Need to redisplay whole line */
140
    }
141
    additional_text = CHAR(STRING_ELT( VECTOR_ELT(ans, ADDITION), 0 ));
142
    alen = strlen(additional_text);
143
    if (alen) {
144
	int cp = *loc;
41070 ripley 145
	memcpy(buf+cp, additional_text, alen+1);
41020 ripley 146
	*loc = cp + alen;
147
    }
148
    return cursor_position;
149
}
150
 
151
 
152
void R_gl_tab_set(void)
153
{
154
    gl_tab_hook = rt_completion;
155
}