This commit is contained in:
anon 2023-08-15 10:56:04 +02:00
parent ac8b1ba6dc
commit 046e3a75f7
10 changed files with 163 additions and 187 deletions

View File

@ -1,12 +1,14 @@
DEBUG:=1
GCC:=0
LIBS:=ncurses readline history
CC:=gcc
CFLAGS:=-Wall -Wextra -Wpedantic
CFLAGS +=$(if $(DEBUG),-O0 -ggdb,-O3 -flto=auto -fomit-frame-pointer)
CFLAGS +=$(if $(SAN),-fsanitize=${SAN})
CPPFLAGS:=-I config/ -I ${CHDRD} ${shell pkg-config --cflags ncurses readline}
LDLIBS=${shell pkg-config --libs ncurses readline}
CPPFLAGS:=-I config/ -I ${CHDRD} ${shell pkg-config --cflags ${LIBS}}
LDLIBS=${shell pkg-config --libs ${LIBS}}
LEX:=flex
LEXD:=src/

View File

@ -26,7 +26,7 @@ Csope is alive and well.
# Interface
<-- Tab -->
+------------Message-------------+ +--------------------------------+
+--Version-----------------Case--+ +--------------------------------+
A |+--------------+---------------+| |+------------------------------+|
| || Input Window | Result window || || ||
| |+--------------+ || ? || ||
@ -36,7 +36,7 @@ Csope is alive and well.
| || | || || ||
| || | || || ||
V |+--------------+---------------+| |+------------------------------+|
+-----------Tool Tips------------+ +--------------------------------+
+---------------------Tool Tips--+ +--------------------------------+
# Usacases
Csope shines at exploring stranger and obsecure code bases due to its TUI.
@ -49,21 +49,29 @@ fixing it would have been a lost cause, if not for Cscope itself. Well, Csope no
# Improvements/Changes
## User side
+ renamed the program, because "cscope" is annoying to type
+ improved gui
+ GNU Readline integration (ie. VI/EMACS mode, command history) /*pending*/
+ Renamed the program, because "cscope" is annoying to type
+ Improved tui
+ GNU Readline/History integration
## To the code
+ nuked autoconf, replaced with single Makefile
+ reorganized main()
+ encapsulated changes to the TUI into display.c
+ encapsulated searching into find.c
+ removed "scanner.l" which seems to be an anchient version (and redundant copy) of "fscanner.l" forgotten by all
+ removed macro hell put in place to allow compiling on a dead badger
+ replaced repeated inline #ifdef KEY_\*-s with guaranteed definitions
+ removed random commets giving tips for and refering to specific issues
+ use stdbool instead of YES/NO macros
+ saved kilobytes by stripping trailing whitespace
+ FILE\* refsfound used to be rewind()-ed everytime the reads were not sequencial
+ Nuked autoconf, replaced with single Makefile
+ Reorganized the control flow
+ Encapsulated changes to the TUI into display.c
+ Encapsulated searching into find.c
+ Removed "scanner.l" which seems to be an anchient version (and redundant copy) of "fscanner.l" forgotten by all
+ Removed macro hell put in place to allow compiling on a dead badger
+ Use stdbool instead of YES/NO macros
+ Saved kilobytes by stripping trailing whitespace
+ ...and much more
# Installation
You will have to compile from source.
After you made sure you have the following (dev) libraries installed:
ncurses
GNU Readline
GNU History (should come with Readline)
Just run:
make
This will yield the executable "scope", which you are free to do whatever with.
# Control flow
...
@ -86,26 +94,25 @@ fixing it would have been a lost cause, if not for Cscope itself. Well, Csope no
| int window_change | Bit mask type of the CH_\* macros. Keeps track of the windows to be refresed on the next run of display(). Could be better utalized.
# TODO /*move soon*/
+ sort out constants.h
+ scrollbar() uses magic int literals?
+ Ordering function declarations in global.h by alpha order is not smart
+ lineflagafterfile is stupid
+ library.h...; "private library", in a program using 90 globals; ffs
+ sort out the global hell
+ was there really ever a scrollbar?
+ handle resizing
+ a search struct could be great for caching and could easy the global situation
+ sort out constants.h
+ scrollbar() uses magic int literals?
+ lineflagafterfile is stupid
+ library.h...; "private library", in a program using 90 globals; ffs
+ sort out the global hell
+ was there really ever a scrollbar?
+ handle resizing
+ a search struct could be great for caching and could ease the global situation
## Original
+ Same capabilities as interactive in non interactive (one shot) mode
+ Provide some how-do-I-use-this-thing doc.
# BUGS
+ Changing text double frees:
free(): double free detected in tcache 2
Aborted
+ Changing text can crash without replacing text and leaving the console ncursed
+ After an attempted change malloc *can* cry and crash
+ Changing text double frees:
free(): double free detected in tcache 2
Aborted
+ Changing text can crash without replacing text and leaving the console ncursed
+ After an attempted change malloc *can* cry and crash
# Future features / contributor wishlist
+ providing support for other languages by integrating new lexers (e.g. ctag's)

View File

@ -35,6 +35,8 @@
# define COLOR_HELP_BG -1
# define COLOR_TOOLTIP_FG COLOR_WHITE
# define COLOR_TOOLTIP_BG COLOR_GREEN
# define COLOR_CASE_FG COLOR_GREEN
# define COLOR_CASE_BG -1
# define COLOR_MESSAGE_FG COLOR_WHITE
# define COLOR_MESSAGE_BG COLOR_BLACK
# define COLOR_PATTERN_FG COLOR_WHITE
@ -78,6 +80,7 @@ enum color_pairs{
COLOR_PAIR_FIELD_SELECTED,
COLOR_PAIR_HELP,
COLOR_PAIR_TOOLTIP,
COLOR_PAIR_CASE,
COLOR_PAIR_PATTERN,
COLOR_PAIR_MESSAGE,
COLOR_PAIR_TABLE_HEADER,

View File

@ -94,6 +94,7 @@ WINDOW *wresult;
WINDOW *whelp;
/* Non-Selectable windows */
WINDOW *wtooltip;
WINDOW *wcase;
/* Selected window pointer */
WINDOW **current_window;
static WINDOW **last_window;
@ -113,6 +114,7 @@ static inline void display_cursor(void);
static inline void display_help(void);
static inline void display_frame(const bool border_only);
static inline void display_mode(void);
static inline void display_case(void);
static inline void display_command_field(void);
static inline void display_results(void);
static inline void display_tooltip(void);
@ -161,6 +163,7 @@ void dispinit(void) {
easy_init_pair(FIELD_SELECTED);
easy_init_pair(HELP);
easy_init_pair(TOOLTIP);
easy_init_pair(CASE);
easy_init_pair(MESSAGE);
easy_init_pair(PATTERN);
easy_init_pair(TABLE_HEADER);
@ -189,6 +192,7 @@ void dispinit(void) {
mdisprefs = result_window_height - (WRESULT_TABLE_BODY_START + 1);
tooltip_width =
MAX(MAX(strlen(tooltip_winput), strlen(tooltip_wmode)), strlen(tooltip_wresult));
static int case_width = sizeof("Case: XXX")-1;
if(mdisprefs <= 0) {
postfatal(PROGRAM_NAME ": screen too small\n");
@ -203,11 +207,12 @@ void dispinit(void) {
rlinit();
/* initialize windows */
winput = newwin(input_window_height, first_col_width, 1, 1);
wmode = newwin(mode_window_height, first_col_width, input_window_height + 1 + 1, 1);
wresult = newwin(result_window_height, second_col_width, 1, first_col_width + 1 + 1);
whelp = newwin(LINES - 2, COLS - 2, 1, 1);
winput = newwin(input_window_height, first_col_width, 1, 1);
wmode = newwin(mode_window_height, first_col_width, input_window_height + 1 + 1, 1);
wresult = newwin(result_window_height, second_col_width, 1, first_col_width + 1 + 1);
whelp = newwin(LINES - 2, COLS - 2, 1, 1);
wtooltip = newwin(1, tooltip_width, LINES - 1, COLS - (tooltip_width + 4));
wcase = newwin(1, case_width, 0, COLS - case_width - 4);
refresh();
current_window = &winput;
@ -261,6 +266,13 @@ static inline void display_help() {
do_press_any_key = true;
}
static inline void display_case(){
wmove(wcase, 0, 0);
wattron(wcase, COLOR_PAIR(COLOR_PAIR_CASE));
waddstr(wcase, (caseless ? "Case: OFF" : "Case: ON"));
wattroff(wcase, COLOR_PAIR(COLOR_PAIR_CASE));
}
static inline void display_frame(const bool border_only) {
wattron(stdscr, COLOR_PAIR(COLOR_PAIR_FRAME));
@ -273,12 +285,6 @@ static inline void display_frame(const bool border_only) {
#else
wprintw(stdscr, PROGRAM_NAME " version %d%s", FILEVERSION, FIXVERSION);
#endif
wmove(stdscr, 0, COLS - (int)sizeof("Case: XXX") - 4);
if(caseless) {
waddstr(stdscr, "Case: ON");
} else {
waddstr(stdscr, "Case: OFF");
}
/* --- */
if(!border_only) {
/* Vertical line */
@ -805,6 +811,7 @@ void display(void) {
lstwin = *current_window;
display_tooltip();
}
if(window_change & CH_CASE) { display_case(); }
if(window_change & CH_INPUT) { display_command_field(); }
if(window_change & CH_RESULT) { display_results(); }
if(window_change & CH_MODE) { display_mode(); }
@ -814,6 +821,7 @@ void display(void) {
wrefresh(wmode);
wrefresh(wresult);
wrefresh(wtooltip);
wrefresh(wcase);
}
window_change = CH_NONE;

View File

@ -80,8 +80,9 @@ enum {
CH_RESULT = 0x0001 << 0,
CH_INPUT = 0x0001 << 1,
CH_MODE = 0x0001 << 2,
CH_HELP = 0x0001 << 3, /* do NOT add to CH_ALL */
CH_ALL = CH_RESULT | CH_INPUT | CH_MODE
CH_CASE = 0x0001 << 3,
CH_HELP = 0x0001 << 4, /* do NOT add to CH_ALL */
CH_ALL = CH_RESULT | CH_INPUT | CH_MODE | CH_CASE
};
enum {
@ -252,7 +253,6 @@ void PCS_reset(void);
void rlinit(void);
void addcmd(int f, char *s);
void addsrcfile(char *path);
void askforchar(void);
void askforreturn(void);
@ -295,7 +295,6 @@ void posterr(char *msg, ...);
void postfatal(const char *msg, ...);
void putposting(char *term, int type);
void fetch_string_from_dbase(char *, size_t);
void resetcmd(void);
void shellpath(char *out, int limit, char *in);
void sourcedir(char *dirlist);
void myungetch(int c);
@ -309,9 +308,6 @@ bool writerefsfound(void);
int findinit(const char *pattern_);
MOUSE *getmouseaction(char leading_char);
struct cmd *currentcmd(void);
struct cmd *prevcmd(void);
struct cmd *nextcmd(void);
int egrep(char *file, FILE *output, char *format);
int hash(char *ss);

View File

@ -1,95 +0,0 @@
/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT falseT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT falseT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol or text cross-reference
*
* command history
*/
#include "global.h"
static struct cmd *tail, *current;
/* add a cmd to the history list */
void addcmd(int f, char *s) /* field number and command text */
{
struct cmd *h;
h = malloc(sizeof(struct cmd));
if(tail) {
tail->next = h;
h->next = 0;
h->prev = tail;
tail = h;
} else {
tail = h;
h->next = h->prev = 0;
}
h->field = f;
h->text = strdup(s);
current = 0;
}
/* return previous history item */
struct cmd *prevcmd(void) {
if(current) {
if(current->prev) /* stay on first item */
return current = current->prev;
else
return current;
} else if(tail)
return current = tail;
else
return NULL;
}
/* return next history item */
struct cmd *nextcmd(void) {
if(current) {
if(current->next) /* stay on first item */
return current = current->next;
else
return current;
} else
return NULL;
}
/* reset current to tail */
void resetcmd(void) {
current = 0;
}
struct cmd *currentcmd(void) {
return current;
}

View File

@ -160,17 +160,14 @@ static int wmode_input(const int c) {
case KEY_DOWN:
case KEY_RIGHT:
field = (field + 1) % FIELDS;
resetcmd();
break;
case ctrl('P'): /* go to previous input field */
case KEY_UP:
case KEY_LEFT:
field = (field + (FIELDS - 1)) % FIELDS;
resetcmd();
break;
case KEY_HOME: /* go to first input field */
field = 0;
resetcmd();
break;
case KEY_LL: /* go to last input field */
curdispline = disprefs;
@ -206,7 +203,6 @@ static int wresult_input(const int c) {
break;
case KEY_LL:
field = FIELDS - 1;
resetcmd();
break;
default:
if(c > mdisprefs) { goto noredisp; }
@ -230,12 +226,10 @@ static int global_input(const int c) {
break;
case ctrl('K'):
field = (field + (FIELDS - 1)) % FIELDS;
resetcmd();
window_change |= CH_MODE;
break;
case ctrl('J'):
field = (field + 1) % FIELDS;
resetcmd();
window_change |= CH_MODE;
break;
case ctrl('H'): /* display previous page */
@ -361,6 +355,13 @@ static int global_input(const int c) {
case ctrl('E'): /* edit all lines */
editall();
break;
case ctrl('S'): // toggle caseless
caseless = !caseless;
egrepcaseless(caseless);
window_change |= CH_CASE;
break;
case EOF:
myexit(0);
default:
return 0;
}

View File

@ -1,6 +1,8 @@
#ifndef KEYS_H
#define KEYS_H
#include <ncurses.h>
/* Key macros */
/* These macros are not guaranteed to be defined,
* however we wish to test for these anyways while

View File

@ -420,7 +420,6 @@ int process_mouse() {
field = p->y1 - FLDLINE;
/* force it into range */
if(field >= FIELDS) { field = FIELDS - 1; }
resetcmd();
return (false);
}

View File

@ -1,18 +1,65 @@
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "global.h"
#include "build.h"
#include <ncurses.h>
static int input_available = 0;
static char input_char;
static int input_char;
char input_line[PATLEN + 1];
/* used for saving a line not [Enter]-ed yet,
* so its not lost if the user scrolls the history
*/
static struct PARTIAL_LINE {
bool is_active;
char* line;
int pos;
} partial_line = {
.line = NULL,
.is_active = true
};
static inline void previous_history_proxy(void);
static inline void next_history_proxy(void);
static inline int rebuild_reference(void);
bool interpret(int c) {
input_char = c;
input_available = 1;
rl_callback_read_char();
/* A switch is faster then binding Readline to a billion functions
* and since KEY_* values can't be bound anyways (values too large
* (because while the first argument of rl_bind_key() is an int,
* only unsigned chars are valid)), handling everything here
* creates consistency too.
*/
switch(c){
case KEY_BACKSPACE:
rl_rubout(1, 0);
break;
case KEY_UP:
previous_history_proxy();
break;
case KEY_DOWN:
next_history_proxy();
break;
case ctrl('R'):
rebuild_reference();
break;
case ESC:
case ctrl('X'):
process_mouse();
break;
default:
input_char = c;
input_available = 1;
rl_callback_read_char();
return 0;
}
//XXX:
// rl_bind_key(ctrl('\\'), /**/); /* bypass bindings */
window_change |= CH_INPUT;
return 0;
}
@ -20,7 +67,7 @@ static int getc_function(FILE *ignore) {
UNUSED(ignore);
input_available = 0;
return (int)input_char;
return input_char;
}
static int input_available_hook() {
@ -34,6 +81,8 @@ static void redisplay_function() {
static void callback_handler(char *line) {
if(!line) { return; }
add_history(line);
switch(input_mode) {
case INPUT_NORMAL:
strncpy(input_line, line, PATLEN);
@ -62,24 +111,7 @@ static void callback_handler(char *line) {
}
}
static int ctrl_z() {
kill(0, SIGTSTP);
return 0;
}
static int toggle_caseless() {
if(caseless == false) {
caseless = true;
postmsg2("Caseless mode is now ON");
} else {
caseless = false;
postmsg2("Caseless mode is now OFF");
}
egrepcaseless(caseless); /* turn on/off -i flag */
return 0;
}
static int rebuild_reference() {
static inline int rebuild_reference() {
if(isuptodate == true) {
postmsg("The -d option prevents rebuilding the symbol database");
return (false);
@ -99,7 +131,41 @@ static int rebuild_reference() {
return (true);
}
static inline void previous_history_proxy(){
HIST_ENTRY* i = previous_history();
if(i){
if(partial_line.is_active){
free(partial_line.line);
partial_line = (struct PARTIAL_LINE){
.line = rl_line_buffer,
.pos = rl_point,
.is_active = false
};
}else{
free(rl_line_buffer);
}
//
rl_line_buffer = strdup(i->line);
rl_point = strlen(rl_line_buffer);
}
}
static inline void next_history_proxy(){
HIST_ENTRY* i = next_history();
if(i){
free(rl_line_buffer);
rl_line_buffer = strdup(i->line);
rl_point = strlen(rl_line_buffer);
}else if(!partial_line.is_active){
rl_line_buffer = strdup(partial_line.line);
rl_point = partial_line.pos;
partial_line.is_active = true;
}
}
void rlinit() {
using_history();
rl_catch_signals = 0;
rl_catch_sigwinch = 0;
rl_prep_term_function = NULL;
@ -110,17 +176,4 @@ void rlinit() {
rl_input_available_hook = input_available_hook;
rl_redisplay_function = redisplay_function;
rl_callback_handler_install("", callback_handler);
rl_bind_key(7,
rl_rubout); // XXX: 7 is backspace for some reason (on my system anyways?)
rl_bind_key(KEY_BACKSPACE, rl_rubout);
rl_bind_key(EOF, myexit);
rl_bind_key(ctrl('Z'), ctrl_z);
rl_bind_key(ctrl('Z'), toggle_caseless);
rl_bind_key(ctrl('R'), rebuild_reference);
rl_bind_key(ESC, process_mouse); /* possible unixpc mouse selection */
rl_bind_key(ctrl('X'), process_mouse); /* mouse selection */
// rl_bind_key(ctrl('\\'), /**/); /* bypass bindings */
}