readline

来自百合仙子's Wiki
跳转到导航 跳转到搜索

操作技巧

在交互命令行中,使用Ctrl+Alt+J可切换到 vi 模式。[1]

文件

头文件: <readline/readline.h> ,编译时库文件参数: -lreadline 。如需要使用历史功能,需要头文件 <readline/history.h>

示例

简单使用

//=====================================================================
// readline 测试
//=====================================================================
#include<stdio.h>
#include<stdlib.h>
#include<readline/readline.h>
#include<readline/history.h>
/* --------------------------------------------------------------------- */
int main(int argc, char **argv){
  char *p;
  while((p=readline("\x1b[1;35m>>\x1b[0m ")) != NULL){
    if(p[0] != '\0'){
      puts(p);
      add_history(p);
    }else{
      free(p);
    }
  }
  putchar('\n');
  return 0;
}
//=====================================================================

如果遇到 EOFreadline 返回 NULL

使用 rl_callback_read_char

rl_callback_read_char [2]可以在文件描述符准备好时再调用。(这里用到了gcc所支持的嵌套函数。)

#include<stdio.h>
#include<readline/readline.h>

int main(void){
  int cont = 1;

  void callback(char *text){
    if(text == NULL){
      rl_callback_handler_remove();
      putchar('\n');
      cont = 0;
    }else{
      printf("%s.\n", text);
    }
  }

  rl_callback_handler_install(">> ", callback);
  while(cont){
    rl_callback_read_char();
  }
  return 0;
}

ncurses 中使用 readline

[3]

C 语言版

注:未做缓冲区溢出检查。

#define _XOPEN_SOURCE 700       /* for wcswidth and 700 is for mbsnrtowcs */
#include<wchar.h>
#include<ncurses.h>		/* ncurses.h includes stdio.h */
#include<stdlib.h>
#include<string.h>
#include<readline/readline.h>
#include<locale.h>

int mygetstr(char *str, int y, int x){
  WINDOW *win;
  int size, col;
  int ok = 0;
  int width;
  wchar_t wstr[80];
  char *p;

  getmaxyx(stdscr, size, col);

  void getaline(char *s){
    str = s;
    rl_callback_handler_remove();
    ok = 1;
  }

  rl_callback_handler_install("", getaline);
  win = newwin(1, col-x, y, x);
  while(1){
    rl_callback_read_char();
    if(ok)
      break;
    werase(win);
    strncpy(str, rl_line_buffer, 80);
    p = str;
    /* how many column chars before cursor occupies? */
    size = mbsnrtowcs(wstr, (const char**)&p, rl_point, 80, NULL);
    width = wcswidth(wstr, size);
    mvwprintw(win, 0, 0, "%s", str);
    /* put the cursor at right column */
    wmove(win, 0, width);
    wrefresh(win);
  }
  delwin(win);
  return 0;
}

int main(){
  char mesg[] = "Enter a string: ";
  char str[80];
  int row, col;

  setlocale(LC_ALL, "");        /* make ncurses handle Chinese correctly */
  initscr();
  getmaxyx(stdscr, row, col);
  mvprintw(row / 2, (col - strlen(mesg)) / 2, "%s", mesg);
  refresh();
  mygetstr(str, row / 2, (col + strlen(mesg)) / 2);
  mvprintw(LINES - 2, 0, "You Entered: %s", str);
  getch();
  endwin();

  return 0;
}

Python

#!/usr/bin/env python3
# vim:fileencoding=utf-8

import sys
import readline
import ctypes
import ctypes.util
import curses
import struct
from charset import strwidth
 
rllib_path = ctypes.util.find_library('readline')
rllib = ctypes.CDLL(rllib_path)
 
def getstr(win, y, x):
  _, col = win.getmaxyx()
  inputbox = curses.newwin(1, col-x, y, x)
  ret = ''
  ok = False
  def callback(s):
    nonlocal ok, ret
    if s is None:
      rllib.rl_callback_handler_remove()
      raise EOFError
    elif not s:
      ok = True
    else:
      ret = s.decode()
      ok = True
  
  cbfunc = ctypes.CFUNCTYPE(None, ctypes.c_char_p)
  
  rllib.rl_callback_handler_install.restype = None
  rllib.rl_callback_handler_install(ctypes.c_char_p(b""), cbfunc(callback))
  
  while True:
    rllib.rl_callback_read_char()
    if ok:
      break
    inputbox.erase()
    # 这样获取的值不对。。。
    # bbuf = ctypes.string_at(rllib.rl_line_buffer)
    buf = readline.get_line_buffer()
    bbuf = buf.encode()
    inputbox.addstr(0, 0, buf)
    rl_point = struct.unpack('I', ctypes.string_at(rllib.rl_point, 4))[0]
    w = strwidth(bbuf[:rl_point].decode())
    inputbox.move(0, w)
    inputbox.refresh()

  del inputbox

  return ret

msg = '输入字符串:'
win = curses.initscr()
curses.noecho()
row, col = win.getmaxyx()
win.addstr(row // 2, (col - strwidth(msg)) // 2, msg)
win.refresh()
s = getstr(win, row // 2, (col + strwidth(msg)) // 2)
win.addstr(row - 2, 0, '你输入了: ' + s)
win.getch()
curses.endwin()

技巧

在提示符中使用 \001\002 来标识不可见字符[4]

参见

外部链接

参考资料