mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 20:55:18 -07:00
vim-patch:8.1.2001: some source files are too big (#21231)
Problem: Some source files are too big.
Solution: Move buffer and window related functions to evalbuffer.c and
evalwindow.c. (Yegappan Lakshmanan, closes vim/vim#4898)
261f346f81
This commit is contained in:
parent
98695b4999
commit
0b79137c59
@ -37,6 +37,7 @@
|
||||
{ include: [ '"drawscreen.h.generated.h"', private, '"nvim/drawscreen.h"', public ] },
|
||||
{ include: [ '"edit.h.generated.h"', private, '"nvim/edit.h"', public ] },
|
||||
{ include: [ '"eval.h.generated.h"', private, '"nvim/eval.h"', public ] },
|
||||
{ include: [ '"eval/buffer.h.generated.h"', private, '"nvim/eval/buffer.h"', public ] },
|
||||
{ include: [ '"eval/decode.h.generated.h"', private, '"nvim/eval/decode.h"', public ] },
|
||||
{ include: [ '"eval/encode.h.generated.h"', private, '"nvim/eval/encode.h"', public ] },
|
||||
{ include: [ '"eval/executor.h.generated.h"', private, '"nvim/eval/executor.h"', public ] },
|
||||
@ -44,6 +45,7 @@
|
||||
{ include: [ '"eval/typval.h.generated.h"', private, '"nvim/eval/typval.h"', public ] },
|
||||
{ include: [ '"eval/userfunc.h.generated.h"', private, '"nvim/eval/userfunc.h"', public ] },
|
||||
{ include: [ '"eval/vars.h.generated.h"', private, '"nvim/eval/vars.h"', public ] },
|
||||
{ include: [ '"eval/window.h.generated.h"', private, '"nvim/eval/window.h"', public ] },
|
||||
{ include: [ '"event/libuv_process.h.generated.h"', private, '"nvim/event/libuv_process.h"', public ] },
|
||||
{ include: [ '"event/loop.h.generated.h"', private, '"nvim/event/loop.h"', public ] },
|
||||
{ include: [ '"event/multiqueue.h.generated.h"', private, '"nvim/event/multiqueue.h"', public ] },
|
||||
|
@ -242,6 +242,14 @@ preprocess_patch() {
|
||||
LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/userfunc\.c/\1\/eval\/userfunc\.c/g' \
|
||||
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
||||
|
||||
# Rename evalbuffer.c to eval/buffer.c
|
||||
LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/evalbuffer\.c/\1\/eval\/buffer\.c/g' \
|
||||
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
||||
|
||||
# Rename evalwindow.c to eval/window.c
|
||||
LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/evalwindow\.c/\1\/eval\/window\.c/g' \
|
||||
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
||||
|
||||
# Rename map.c to mapping.c
|
||||
LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/map\(\.[ch]\)/\1\/mapping\2/g' \
|
||||
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/autocmd.h"
|
||||
#include "nvim/buffer_defs.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/globals.h"
|
||||
#include "nvim/memory.h"
|
||||
#include "nvim/option.h"
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nvim/buffer_defs.h"
|
||||
#include "nvim/cursor.h"
|
||||
#include "nvim/drawscreen.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/ex_docmd.h"
|
||||
#include "nvim/gettext.h"
|
||||
#include "nvim/globals.h"
|
||||
|
@ -13,9 +13,9 @@
|
||||
#include "nvim/ascii.h"
|
||||
#include "nvim/buffer.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/ex_cmds.h"
|
||||
#include "nvim/ex_cmds2.h"
|
||||
#include "nvim/ex_cmds_defs.h"
|
||||
|
@ -3961,30 +3961,6 @@ char *buf_spname(buf_T *buf)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Find a window for buffer "buf".
|
||||
/// If found true is returned and "wp" and "tp" are set to
|
||||
/// the window and tabpage.
|
||||
/// If not found, false is returned.
|
||||
///
|
||||
/// @param buf buffer to find a window for
|
||||
/// @param[out] wp stores the found window
|
||||
/// @param[out] tp stores the found tabpage
|
||||
///
|
||||
/// @return true if a window was found for the buffer.
|
||||
bool find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp)
|
||||
{
|
||||
*wp = NULL;
|
||||
*tp = NULL;
|
||||
FOR_ALL_TAB_WINDOWS(tp2, wp2) {
|
||||
if (wp2->w_buffer == buf) {
|
||||
*tp = tp2;
|
||||
*wp = wp2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int buf_signcols_inner(buf_T *buf, int maximum)
|
||||
{
|
||||
sign_entry_T *sign; // a sign in the sign list
|
||||
|
306
src/nvim/eval.c
306
src/nvim/eval.c
@ -16,7 +16,6 @@
|
||||
#include "nvim/ascii.h"
|
||||
#include "nvim/buffer.h"
|
||||
#include "nvim/buffer_defs.h"
|
||||
#include "nvim/change.h"
|
||||
#include "nvim/channel.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/cmdhist.h"
|
||||
@ -73,13 +72,11 @@
|
||||
#include "nvim/regexp.h"
|
||||
#include "nvim/runtime.h"
|
||||
#include "nvim/search.h"
|
||||
#include "nvim/sign.h"
|
||||
#include "nvim/strings.h"
|
||||
#include "nvim/tag.h"
|
||||
#include "nvim/types.h"
|
||||
#include "nvim/ui.h"
|
||||
#include "nvim/ui_compositor.h"
|
||||
#include "nvim/undo.h"
|
||||
#include "nvim/usercmd.h"
|
||||
#include "nvim/version.h"
|
||||
#include "nvim/vim.h"
|
||||
@ -1031,17 +1028,6 @@ void restore_vimvar(int idx, typval_T *save_tv)
|
||||
}
|
||||
}
|
||||
|
||||
/// If there is a window for "curbuf", make it the current window.
|
||||
void find_win_for_curbuf(void)
|
||||
{
|
||||
for (wininfo_T *wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next) {
|
||||
if (wip->wi_win != NULL) {
|
||||
curwin = wip->wi_win;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate an expression to a list with suggestions.
|
||||
/// For the "expr:" part of 'spellsuggest'.
|
||||
///
|
||||
@ -4792,19 +4778,6 @@ void assert_error(garray_T *gap)
|
||||
(const char *)gap->ga_data, (ptrdiff_t)gap->ga_len);
|
||||
}
|
||||
|
||||
/// Find a window: When using a Window ID in any tab page, when using a number
|
||||
/// in the current tab page.
|
||||
win_T *find_win_by_nr_or_id(typval_T *vp)
|
||||
{
|
||||
int nr = (int)tv_get_number_chk(vp, NULL);
|
||||
|
||||
if (nr >= LOWEST_WIN_ID) {
|
||||
return win_id2wp((int)tv_get_number(vp));
|
||||
}
|
||||
|
||||
return find_win_by_nr(vp, NULL);
|
||||
}
|
||||
|
||||
/// Implementation of map() and filter().
|
||||
void filter_map(typval_T *argvars, typval_T *rettv, int map)
|
||||
{
|
||||
@ -5161,46 +5134,6 @@ theend:
|
||||
xfree(trans_name);
|
||||
}
|
||||
|
||||
/// @return buffer options, variables and other attributes in a dictionary.
|
||||
dict_T *get_buffer_info(buf_T *buf)
|
||||
{
|
||||
dict_T *const dict = tv_dict_alloc();
|
||||
|
||||
tv_dict_add_nr(dict, S_LEN("bufnr"), buf->b_fnum);
|
||||
tv_dict_add_str(dict, S_LEN("name"),
|
||||
buf->b_ffname != NULL ? (const char *)buf->b_ffname : "");
|
||||
tv_dict_add_nr(dict, S_LEN("lnum"),
|
||||
buf == curbuf ? curwin->w_cursor.lnum : buflist_findlnum(buf));
|
||||
tv_dict_add_nr(dict, S_LEN("linecount"), buf->b_ml.ml_line_count);
|
||||
tv_dict_add_nr(dict, S_LEN("loaded"), buf->b_ml.ml_mfp != NULL);
|
||||
tv_dict_add_nr(dict, S_LEN("listed"), buf->b_p_bl);
|
||||
tv_dict_add_nr(dict, S_LEN("changed"), bufIsChanged(buf));
|
||||
tv_dict_add_nr(dict, S_LEN("changedtick"), buf_get_changedtick(buf));
|
||||
tv_dict_add_nr(dict, S_LEN("hidden"),
|
||||
buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
|
||||
|
||||
// Get a reference to buffer variables
|
||||
tv_dict_add_dict(dict, S_LEN("variables"), buf->b_vars);
|
||||
|
||||
// List of windows displaying this buffer
|
||||
list_T *const windows = tv_list_alloc(kListLenMayKnow);
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (wp->w_buffer == buf) {
|
||||
tv_list_append_number(windows, (varnumber_T)wp->handle);
|
||||
}
|
||||
}
|
||||
tv_dict_add_list(dict, S_LEN("windows"), windows);
|
||||
|
||||
if (buf->b_signlist != NULL) {
|
||||
// List of signs placed in this buffer
|
||||
tv_dict_add_list(dict, S_LEN("signs"), get_buffer_signs(buf));
|
||||
}
|
||||
|
||||
tv_dict_add_nr(dict, S_LEN("lastused"), buf->b_last_used);
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
/// Get the line number from VimL object
|
||||
///
|
||||
/// @note Unlike tv_get_lnum(), this one supports only "$" special string.
|
||||
@ -5224,115 +5157,6 @@ linenr_T tv_get_lnum_buf(const typval_T *const tv, const buf_T *const buf)
|
||||
return (linenr_T)tv_get_number_chk(tv, NULL);
|
||||
}
|
||||
|
||||
/// @return information (variables, options, etc.) about a tab page
|
||||
/// as a dictionary.
|
||||
dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx)
|
||||
{
|
||||
dict_T *const dict = tv_dict_alloc();
|
||||
|
||||
tv_dict_add_nr(dict, S_LEN("tabnr"), tp_idx);
|
||||
|
||||
list_T *const l = tv_list_alloc(kListLenMayKnow);
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
|
||||
tv_list_append_number(l, (varnumber_T)wp->handle);
|
||||
}
|
||||
tv_dict_add_list(dict, S_LEN("windows"), l);
|
||||
|
||||
// Make a reference to tabpage variables
|
||||
tv_dict_add_dict(dict, S_LEN("variables"), tp->tp_vars);
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
/// @return information about a window as a dictionary.
|
||||
dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
|
||||
{
|
||||
dict_T *const dict = tv_dict_alloc();
|
||||
|
||||
// make sure w_botline is valid
|
||||
validate_botline(wp);
|
||||
|
||||
tv_dict_add_nr(dict, S_LEN("tabnr"), tpnr);
|
||||
tv_dict_add_nr(dict, S_LEN("winnr"), winnr);
|
||||
tv_dict_add_nr(dict, S_LEN("winid"), wp->handle);
|
||||
tv_dict_add_nr(dict, S_LEN("height"), wp->w_height_inner);
|
||||
tv_dict_add_nr(dict, S_LEN("winrow"), wp->w_winrow + 1);
|
||||
tv_dict_add_nr(dict, S_LEN("topline"), wp->w_topline);
|
||||
tv_dict_add_nr(dict, S_LEN("botline"), wp->w_botline - 1);
|
||||
tv_dict_add_nr(dict, S_LEN("winbar"), wp->w_winbar_height);
|
||||
tv_dict_add_nr(dict, S_LEN("width"), wp->w_width_inner);
|
||||
tv_dict_add_nr(dict, S_LEN("bufnr"), wp->w_buffer->b_fnum);
|
||||
tv_dict_add_nr(dict, S_LEN("wincol"), wp->w_wincol + 1);
|
||||
tv_dict_add_nr(dict, S_LEN("textoff"), win_col_off(wp));
|
||||
tv_dict_add_nr(dict, S_LEN("terminal"), bt_terminal(wp->w_buffer));
|
||||
tv_dict_add_nr(dict, S_LEN("quickfix"), bt_quickfix(wp->w_buffer));
|
||||
tv_dict_add_nr(dict, S_LEN("loclist"),
|
||||
(bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
|
||||
|
||||
// Add a reference to window variables
|
||||
tv_dict_add_dict(dict, S_LEN("variables"), wp->w_vars);
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
/// Find window specified by "vp" in tabpage "tp".
|
||||
///
|
||||
/// @param tp NULL for current tab page
|
||||
win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp)
|
||||
{
|
||||
int nr = (int)tv_get_number_chk(vp, NULL);
|
||||
|
||||
if (nr < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nr == 0) {
|
||||
return curwin;
|
||||
}
|
||||
|
||||
// This method accepts NULL as an alias for curtab.
|
||||
if (tp == NULL) {
|
||||
tp = curtab;
|
||||
}
|
||||
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
|
||||
if (nr >= LOWEST_WIN_ID) {
|
||||
if (wp->handle == nr) {
|
||||
return wp;
|
||||
}
|
||||
} else if (--nr <= 0) {
|
||||
return wp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Find window specified by "wvp" in tabpage "tvp".
|
||||
win_T *find_tabwin(typval_T *wvp, typval_T *tvp)
|
||||
{
|
||||
win_T *wp = NULL;
|
||||
tabpage_T *tp = NULL;
|
||||
|
||||
if (wvp->v_type != VAR_UNKNOWN) {
|
||||
if (tvp->v_type != VAR_UNKNOWN) {
|
||||
long n = tv_get_number(tvp);
|
||||
if (n >= 0) {
|
||||
tp = find_tabpage((int)n);
|
||||
}
|
||||
} else {
|
||||
tp = curtab;
|
||||
}
|
||||
|
||||
if (tp != NULL) {
|
||||
wp = find_win_by_nr(wvp, tp);
|
||||
}
|
||||
} else {
|
||||
wp = curwin;
|
||||
}
|
||||
|
||||
return wp;
|
||||
}
|
||||
|
||||
/// This function is used by f_input() and f_inputdialog() functions. The third
|
||||
/// argument to f_input() specifies the type of completion to use at the
|
||||
/// prompt. The third argument to f_inputdialog() specifies the value to return
|
||||
@ -5554,136 +5378,6 @@ void screenchar_adjust(ScreenGrid **grid, int *row, int *col)
|
||||
*col -= (*grid)->comp_col;
|
||||
}
|
||||
|
||||
/// Set line or list of lines in buffer "buf" to "lines".
|
||||
/// Any type is allowed and converted to a string.
|
||||
void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, typval_T *lines, typval_T *rettv)
|
||||
FUNC_ATTR_NONNULL_ARG(4, 5)
|
||||
{
|
||||
linenr_T lnum = lnum_arg + (append ? 1 : 0);
|
||||
long added = 0;
|
||||
buf_T *curbuf_save = NULL;
|
||||
win_T *curwin_save = NULL;
|
||||
const bool is_curbuf = buf == curbuf;
|
||||
const bool save_VIsual_active = VIsual_active;
|
||||
|
||||
// When using the current buffer ml_mfp will be set if needed. Useful when
|
||||
// setline() is used on startup. For other buffers the buffer must be
|
||||
// loaded.
|
||||
if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1) {
|
||||
rettv->vval.v_number = 1; // FAIL
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_curbuf) {
|
||||
VIsual_active = false;
|
||||
curbuf_save = curbuf;
|
||||
curwin_save = curwin;
|
||||
curbuf = buf;
|
||||
find_win_for_curbuf();
|
||||
}
|
||||
|
||||
linenr_T append_lnum;
|
||||
if (append) {
|
||||
// appendbufline() uses the line number below which we insert
|
||||
append_lnum = lnum - 1;
|
||||
} else {
|
||||
// setbufline() uses the line number above which we insert, we only
|
||||
// append if it's below the last line
|
||||
append_lnum = curbuf->b_ml.ml_line_count;
|
||||
}
|
||||
|
||||
list_T *l = NULL;
|
||||
listitem_T *li = NULL;
|
||||
char *line = NULL;
|
||||
if (lines->v_type == VAR_LIST) {
|
||||
l = lines->vval.v_list;
|
||||
if (l == NULL || tv_list_len(l) == 0) {
|
||||
// set proper return code
|
||||
if (lnum > curbuf->b_ml.ml_line_count) {
|
||||
rettv->vval.v_number = 1; // FAIL
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
li = tv_list_first(l);
|
||||
} else {
|
||||
line = typval_tostring(lines, false);
|
||||
}
|
||||
|
||||
// Default result is zero == OK.
|
||||
for (;;) {
|
||||
if (lines->v_type == VAR_LIST) {
|
||||
// List argument, get next string.
|
||||
if (li == NULL) {
|
||||
break;
|
||||
}
|
||||
xfree(line);
|
||||
line = typval_tostring(TV_LIST_ITEM_TV(li), false);
|
||||
li = TV_LIST_ITEM_NEXT(l, li);
|
||||
}
|
||||
|
||||
rettv->vval.v_number = 1; // FAIL
|
||||
if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// When coming here from Insert mode, sync undo, so that this can be
|
||||
// undone separately from what was previously inserted.
|
||||
if (u_sync_once == 2) {
|
||||
u_sync_once = 1; // notify that u_sync() was called
|
||||
u_sync(true);
|
||||
}
|
||||
|
||||
if (!append && lnum <= curbuf->b_ml.ml_line_count) {
|
||||
// Existing line, replace it.
|
||||
int old_len = (int)strlen(ml_get(lnum));
|
||||
if (u_savesub(lnum) == OK
|
||||
&& ml_replace(lnum, line, true) == OK) {
|
||||
inserted_bytes(lnum, 0, old_len, (int)strlen(line));
|
||||
if (is_curbuf && lnum == curwin->w_cursor.lnum) {
|
||||
check_cursor_col();
|
||||
}
|
||||
rettv->vval.v_number = 0; // OK
|
||||
}
|
||||
} else if (added > 0 || u_save(lnum - 1, lnum) == OK) {
|
||||
// append the line.
|
||||
added++;
|
||||
if (ml_append(lnum - 1, line, 0, false) == OK) {
|
||||
rettv->vval.v_number = 0; // OK
|
||||
}
|
||||
}
|
||||
|
||||
if (l == NULL) { // only one string argument
|
||||
break;
|
||||
}
|
||||
lnum++;
|
||||
}
|
||||
xfree(line);
|
||||
|
||||
if (added > 0) {
|
||||
appended_lines_mark(append_lnum, added);
|
||||
|
||||
// Only adjust the cursor for buffers other than the current, unless it
|
||||
// is the current window. For curbuf and other windows it has been done
|
||||
// in mark_adjust_internal().
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (wp->w_buffer == buf
|
||||
&& (wp->w_buffer != curbuf || wp == curwin)
|
||||
&& wp->w_cursor.lnum > append_lnum) {
|
||||
wp->w_cursor.lnum += (linenr_T)added;
|
||||
}
|
||||
}
|
||||
check_cursor_col();
|
||||
update_topline(curwin);
|
||||
}
|
||||
|
||||
done:
|
||||
if (!is_curbuf) {
|
||||
curbuf = curbuf_save;
|
||||
curwin = curwin_save;
|
||||
VIsual_active = save_VIsual_active;
|
||||
}
|
||||
}
|
||||
|
||||
/// "stdpath()" helper for list results
|
||||
void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
|
700
src/nvim/eval/buffer.c
Normal file
700
src/nvim/eval/buffer.c
Normal file
@ -0,0 +1,700 @@
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
||||
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
// eval/buffer.c: Buffer related builtin functions
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nvim/ascii.h"
|
||||
#include "nvim/autocmd.h"
|
||||
#include "nvim/buffer.h"
|
||||
#include "nvim/change.h"
|
||||
#include "nvim/cursor.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/buffer.h"
|
||||
#include "nvim/eval/funcs.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/globals.h"
|
||||
#include "nvim/macros.h"
|
||||
#include "nvim/memline.h"
|
||||
#include "nvim/memory.h"
|
||||
#include "nvim/move.h"
|
||||
#include "nvim/path.h"
|
||||
#include "nvim/pos.h"
|
||||
#include "nvim/sign.h"
|
||||
#include "nvim/types.h"
|
||||
#include "nvim/undo.h"
|
||||
#include "nvim/vim.h"
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "eval/buffer.c.generated.h"
|
||||
#endif
|
||||
|
||||
/// Find a buffer by number or exact name.
|
||||
buf_T *find_buffer(typval_T *avar)
|
||||
{
|
||||
buf_T *buf = NULL;
|
||||
|
||||
if (avar->v_type == VAR_NUMBER) {
|
||||
buf = buflist_findnr((int)avar->vval.v_number);
|
||||
} else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) {
|
||||
buf = buflist_findname_exp(avar->vval.v_string);
|
||||
if (buf == NULL) {
|
||||
// No full path name match, try a match with a URL or a "nofile"
|
||||
// buffer, these don't use the full path.
|
||||
FOR_ALL_BUFFERS(bp) {
|
||||
if (bp->b_fname != NULL
|
||||
&& (path_with_url(bp->b_fname) || bt_nofilename(bp))
|
||||
&& strcmp(bp->b_fname, avar->vval.v_string) == 0) {
|
||||
buf = bp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/// If there is a window for "curbuf", make it the current window.
|
||||
static void find_win_for_curbuf(void)
|
||||
{
|
||||
for (wininfo_T *wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next) {
|
||||
if (wip->wi_win != NULL) {
|
||||
curwin = wip->wi_win;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set line or list of lines in buffer "buf" to "lines".
|
||||
/// Any type is allowed and converted to a string.
|
||||
static void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, typval_T *lines,
|
||||
typval_T *rettv)
|
||||
FUNC_ATTR_NONNULL_ARG(4, 5)
|
||||
{
|
||||
linenr_T lnum = lnum_arg + (append ? 1 : 0);
|
||||
long added = 0;
|
||||
buf_T *curbuf_save = NULL;
|
||||
win_T *curwin_save = NULL;
|
||||
const bool is_curbuf = buf == curbuf;
|
||||
const bool save_VIsual_active = VIsual_active;
|
||||
|
||||
// When using the current buffer ml_mfp will be set if needed. Useful when
|
||||
// setline() is used on startup. For other buffers the buffer must be
|
||||
// loaded.
|
||||
if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1) {
|
||||
rettv->vval.v_number = 1; // FAIL
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_curbuf) {
|
||||
VIsual_active = false;
|
||||
curbuf_save = curbuf;
|
||||
curwin_save = curwin;
|
||||
curbuf = buf;
|
||||
find_win_for_curbuf();
|
||||
}
|
||||
|
||||
linenr_T append_lnum;
|
||||
if (append) {
|
||||
// appendbufline() uses the line number below which we insert
|
||||
append_lnum = lnum - 1;
|
||||
} else {
|
||||
// setbufline() uses the line number above which we insert, we only
|
||||
// append if it's below the last line
|
||||
append_lnum = curbuf->b_ml.ml_line_count;
|
||||
}
|
||||
|
||||
list_T *l = NULL;
|
||||
listitem_T *li = NULL;
|
||||
char *line = NULL;
|
||||
if (lines->v_type == VAR_LIST) {
|
||||
l = lines->vval.v_list;
|
||||
if (l == NULL || tv_list_len(l) == 0) {
|
||||
// set proper return code
|
||||
if (lnum > curbuf->b_ml.ml_line_count) {
|
||||
rettv->vval.v_number = 1; // FAIL
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
li = tv_list_first(l);
|
||||
} else {
|
||||
line = typval_tostring(lines, false);
|
||||
}
|
||||
|
||||
// Default result is zero == OK.
|
||||
for (;;) {
|
||||
if (lines->v_type == VAR_LIST) {
|
||||
// List argument, get next string.
|
||||
if (li == NULL) {
|
||||
break;
|
||||
}
|
||||
xfree(line);
|
||||
line = typval_tostring(TV_LIST_ITEM_TV(li), false);
|
||||
li = TV_LIST_ITEM_NEXT(l, li);
|
||||
}
|
||||
|
||||
rettv->vval.v_number = 1; // FAIL
|
||||
if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// When coming here from Insert mode, sync undo, so that this can be
|
||||
// undone separately from what was previously inserted.
|
||||
if (u_sync_once == 2) {
|
||||
u_sync_once = 1; // notify that u_sync() was called
|
||||
u_sync(true);
|
||||
}
|
||||
|
||||
if (!append && lnum <= curbuf->b_ml.ml_line_count) {
|
||||
// Existing line, replace it.
|
||||
int old_len = (int)strlen(ml_get(lnum));
|
||||
if (u_savesub(lnum) == OK
|
||||
&& ml_replace(lnum, line, true) == OK) {
|
||||
inserted_bytes(lnum, 0, old_len, (int)strlen(line));
|
||||
if (is_curbuf && lnum == curwin->w_cursor.lnum) {
|
||||
check_cursor_col();
|
||||
}
|
||||
rettv->vval.v_number = 0; // OK
|
||||
}
|
||||
} else if (added > 0 || u_save(lnum - 1, lnum) == OK) {
|
||||
// append the line.
|
||||
added++;
|
||||
if (ml_append(lnum - 1, line, 0, false) == OK) {
|
||||
rettv->vval.v_number = 0; // OK
|
||||
}
|
||||
}
|
||||
|
||||
if (l == NULL) { // only one string argument
|
||||
break;
|
||||
}
|
||||
lnum++;
|
||||
}
|
||||
xfree(line);
|
||||
|
||||
if (added > 0) {
|
||||
appended_lines_mark(append_lnum, added);
|
||||
|
||||
// Only adjust the cursor for buffers other than the current, unless it
|
||||
// is the current window. For curbuf and other windows it has been done
|
||||
// in mark_adjust_internal().
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (wp->w_buffer == buf
|
||||
&& (wp->w_buffer != curbuf || wp == curwin)
|
||||
&& wp->w_cursor.lnum > append_lnum) {
|
||||
wp->w_cursor.lnum += (linenr_T)added;
|
||||
}
|
||||
}
|
||||
check_cursor_col();
|
||||
update_topline(curwin);
|
||||
}
|
||||
|
||||
done:
|
||||
if (!is_curbuf) {
|
||||
curbuf = curbuf_save;
|
||||
curwin = curwin_save;
|
||||
VIsual_active = save_VIsual_active;
|
||||
}
|
||||
}
|
||||
|
||||
/// "append(lnum, string/list)" function
|
||||
void f_append(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
const int did_emsg_before = did_emsg;
|
||||
const linenr_T lnum = tv_get_lnum(&argvars[0]);
|
||||
if (did_emsg == did_emsg_before) {
|
||||
set_buffer_lines(curbuf, lnum, true, &argvars[1], rettv);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set or append lines to a buffer.
|
||||
static void buf_set_append_line(typval_T *argvars, typval_T *rettv, bool append)
|
||||
{
|
||||
const int did_emsg_before = did_emsg;
|
||||
buf_T *const buf = tv_get_buf(&argvars[0], false);
|
||||
if (buf == NULL) {
|
||||
rettv->vval.v_number = 1; // FAIL
|
||||
} else {
|
||||
const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
|
||||
if (did_emsg == did_emsg_before) {
|
||||
set_buffer_lines(buf, lnum, append, &argvars[2], rettv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// "appendbufline(buf, lnum, string/list)" function
|
||||
void f_appendbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
buf_set_append_line(argvars, rettv, true);
|
||||
}
|
||||
|
||||
/// "bufadd(expr)" function
|
||||
void f_bufadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
char_u *name = (char_u *)tv_get_string(&argvars[0]);
|
||||
|
||||
rettv->vval.v_number = buflist_add(*name == NUL ? NULL : (char *)name, 0);
|
||||
}
|
||||
|
||||
/// "bufexists(expr)" function
|
||||
void f_bufexists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
|
||||
}
|
||||
|
||||
/// "buflisted(expr)" function
|
||||
void f_buflisted(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
buf_T *buf;
|
||||
|
||||
buf = find_buffer(&argvars[0]);
|
||||
rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
|
||||
}
|
||||
|
||||
/// "bufload(expr)" function
|
||||
void f_bufload(typval_T *argvars, typval_T *unused, EvalFuncData fptr)
|
||||
{
|
||||
buf_T *buf = get_buf_arg(&argvars[0]);
|
||||
|
||||
if (buf != NULL && buf->b_ml.ml_mfp == NULL) {
|
||||
aco_save_T aco;
|
||||
|
||||
aucmd_prepbuf(&aco, buf);
|
||||
swap_exists_action = SEA_NONE;
|
||||
open_buffer(false, NULL, 0);
|
||||
aucmd_restbuf(&aco);
|
||||
}
|
||||
}
|
||||
|
||||
/// "bufloaded(expr)" function
|
||||
void f_bufloaded(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
buf_T *buf;
|
||||
|
||||
buf = find_buffer(&argvars[0]);
|
||||
rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
|
||||
}
|
||||
|
||||
/// "bufname(expr)" function
|
||||
void f_bufname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
const buf_T *buf;
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
if (argvars[0].v_type == VAR_UNKNOWN) {
|
||||
buf = curbuf;
|
||||
} else {
|
||||
buf = tv_get_buf_from_arg(&argvars[0]);
|
||||
}
|
||||
if (buf != NULL && buf->b_fname != NULL) {
|
||||
rettv->vval.v_string = xstrdup(buf->b_fname);
|
||||
}
|
||||
}
|
||||
|
||||
/// "bufnr(expr)" function
|
||||
void f_bufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
const buf_T *buf;
|
||||
bool error = false;
|
||||
|
||||
rettv->vval.v_number = -1;
|
||||
|
||||
if (argvars[0].v_type == VAR_UNKNOWN) {
|
||||
buf = curbuf;
|
||||
} else {
|
||||
// Don't use tv_get_buf_from_arg(); we continue if the buffer wasn't found
|
||||
// and the second argument isn't zero, but we want to return early if the
|
||||
// first argument isn't a string or number so only one error is shown.
|
||||
if (!tv_check_str_or_nr(&argvars[0])) {
|
||||
return;
|
||||
}
|
||||
emsg_off++;
|
||||
buf = tv_get_buf(&argvars[0], false);
|
||||
emsg_off--;
|
||||
}
|
||||
|
||||
// If the buffer isn't found and the second argument is not zero create a
|
||||
// new buffer.
|
||||
const char *name;
|
||||
if (buf == NULL
|
||||
&& argvars[1].v_type != VAR_UNKNOWN
|
||||
&& tv_get_number_chk(&argvars[1], &error) != 0
|
||||
&& !error
|
||||
&& (name = tv_get_string_chk(&argvars[0])) != NULL) {
|
||||
buf = buflist_new((char *)name, NULL, 1, 0);
|
||||
}
|
||||
|
||||
if (buf != NULL) {
|
||||
rettv->vval.v_number = buf->b_fnum;
|
||||
}
|
||||
}
|
||||
|
||||
static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr)
|
||||
{
|
||||
const buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
|
||||
if (buf == NULL) { // no need to search if invalid arg or buffer not found
|
||||
rettv->vval.v_number = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int winnr = 0;
|
||||
int winid;
|
||||
bool found_buf = false;
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
winnr++;
|
||||
if (wp->w_buffer == buf) {
|
||||
found_buf = true;
|
||||
winid = wp->handle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rettv->vval.v_number = (found_buf ? (get_nr ? winnr : winid) : -1);
|
||||
}
|
||||
|
||||
/// "bufwinid(nr)" function
|
||||
void f_bufwinid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
buf_win_common(argvars, rettv, false);
|
||||
}
|
||||
|
||||
/// "bufwinnr(nr)" function
|
||||
void f_bufwinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
buf_win_common(argvars, rettv, true);
|
||||
}
|
||||
|
||||
/// "deletebufline()" function
|
||||
void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
const int did_emsg_before = did_emsg;
|
||||
rettv->vval.v_number = 1; // FAIL by default
|
||||
buf_T *const buf = tv_get_buf(&argvars[0], false);
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
const bool is_curbuf = buf == curbuf;
|
||||
const bool save_VIsual_active = VIsual_active;
|
||||
|
||||
linenr_T last;
|
||||
const linenr_T first = tv_get_lnum_buf(&argvars[1], buf);
|
||||
if (did_emsg > did_emsg_before) {
|
||||
return;
|
||||
}
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
last = tv_get_lnum_buf(&argvars[2], buf);
|
||||
} else {
|
||||
last = first;
|
||||
}
|
||||
|
||||
if (buf->b_ml.ml_mfp == NULL || first < 1
|
||||
|| first > buf->b_ml.ml_line_count || last < first) {
|
||||
return;
|
||||
}
|
||||
|
||||
buf_T *curbuf_save = NULL;
|
||||
win_T *curwin_save = NULL;
|
||||
// After this don't use "return", goto "cleanup"!
|
||||
if (!is_curbuf) {
|
||||
VIsual_active = false;
|
||||
curbuf_save = curbuf;
|
||||
curwin_save = curwin;
|
||||
curbuf = buf;
|
||||
find_win_for_curbuf();
|
||||
}
|
||||
if (last > curbuf->b_ml.ml_line_count) {
|
||||
last = curbuf->b_ml.ml_line_count;
|
||||
}
|
||||
const long count = last - first + 1;
|
||||
|
||||
// When coming here from Insert mode, sync undo, so that this can be
|
||||
// undone separately from what was previously inserted.
|
||||
if (u_sync_once == 2) {
|
||||
u_sync_once = 1; // notify that u_sync() was called
|
||||
u_sync(true);
|
||||
}
|
||||
|
||||
if (u_save(first - 1, last + 1) == FAIL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (linenr_T lnum = first; lnum <= last; lnum++) {
|
||||
ml_delete(first, true);
|
||||
}
|
||||
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (wp->w_buffer == buf) {
|
||||
if (wp->w_cursor.lnum > last) {
|
||||
wp->w_cursor.lnum -= (linenr_T)count;
|
||||
} else if (wp->w_cursor.lnum > first) {
|
||||
wp->w_cursor.lnum = first;
|
||||
}
|
||||
if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) {
|
||||
wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
check_cursor_col();
|
||||
deleted_lines_mark(first, count);
|
||||
rettv->vval.v_number = 0; // OK
|
||||
|
||||
cleanup:
|
||||
if (!is_curbuf) {
|
||||
curbuf = curbuf_save;
|
||||
curwin = curwin_save;
|
||||
VIsual_active = save_VIsual_active;
|
||||
}
|
||||
}
|
||||
|
||||
/// @return buffer options, variables and other attributes in a dictionary.
|
||||
static dict_T *get_buffer_info(buf_T *buf)
|
||||
{
|
||||
dict_T *const dict = tv_dict_alloc();
|
||||
|
||||
tv_dict_add_nr(dict, S_LEN("bufnr"), buf->b_fnum);
|
||||
tv_dict_add_str(dict, S_LEN("name"),
|
||||
buf->b_ffname != NULL ? (const char *)buf->b_ffname : "");
|
||||
tv_dict_add_nr(dict, S_LEN("lnum"),
|
||||
buf == curbuf ? curwin->w_cursor.lnum : buflist_findlnum(buf));
|
||||
tv_dict_add_nr(dict, S_LEN("linecount"), buf->b_ml.ml_line_count);
|
||||
tv_dict_add_nr(dict, S_LEN("loaded"), buf->b_ml.ml_mfp != NULL);
|
||||
tv_dict_add_nr(dict, S_LEN("listed"), buf->b_p_bl);
|
||||
tv_dict_add_nr(dict, S_LEN("changed"), bufIsChanged(buf));
|
||||
tv_dict_add_nr(dict, S_LEN("changedtick"), buf_get_changedtick(buf));
|
||||
tv_dict_add_nr(dict, S_LEN("hidden"),
|
||||
buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
|
||||
|
||||
// Get a reference to buffer variables
|
||||
tv_dict_add_dict(dict, S_LEN("variables"), buf->b_vars);
|
||||
|
||||
// List of windows displaying this buffer
|
||||
list_T *const windows = tv_list_alloc(kListLenMayKnow);
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (wp->w_buffer == buf) {
|
||||
tv_list_append_number(windows, (varnumber_T)wp->handle);
|
||||
}
|
||||
}
|
||||
tv_dict_add_list(dict, S_LEN("windows"), windows);
|
||||
|
||||
if (buf->b_signlist != NULL) {
|
||||
// List of signs placed in this buffer
|
||||
tv_dict_add_list(dict, S_LEN("signs"), get_buffer_signs(buf));
|
||||
}
|
||||
|
||||
tv_dict_add_nr(dict, S_LEN("lastused"), buf->b_last_used);
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
/// "getbufinfo()" function
|
||||
void f_getbufinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
buf_T *argbuf = NULL;
|
||||
bool filtered = false;
|
||||
bool sel_buflisted = false;
|
||||
bool sel_bufloaded = false;
|
||||
bool sel_bufmodified = false;
|
||||
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
|
||||
// List of all the buffers or selected buffers
|
||||
if (argvars[0].v_type == VAR_DICT) {
|
||||
dict_T *sel_d = argvars[0].vval.v_dict;
|
||||
|
||||
if (sel_d != NULL) {
|
||||
dictitem_T *di;
|
||||
|
||||
filtered = true;
|
||||
|
||||
di = tv_dict_find(sel_d, S_LEN("buflisted"));
|
||||
if (di != NULL && tv_get_number(&di->di_tv)) {
|
||||
sel_buflisted = true;
|
||||
}
|
||||
|
||||
di = tv_dict_find(sel_d, S_LEN("bufloaded"));
|
||||
if (di != NULL && tv_get_number(&di->di_tv)) {
|
||||
sel_bufloaded = true;
|
||||
}
|
||||
di = tv_dict_find(sel_d, S_LEN("bufmodified"));
|
||||
if (di != NULL && tv_get_number(&di->di_tv)) {
|
||||
sel_bufmodified = true;
|
||||
}
|
||||
}
|
||||
} else if (argvars[0].v_type != VAR_UNKNOWN) {
|
||||
// Information about one buffer. Argument specifies the buffer
|
||||
argbuf = tv_get_buf_from_arg(&argvars[0]);
|
||||
if (argbuf == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Return information about all the buffers or a specified buffer
|
||||
FOR_ALL_BUFFERS(buf) {
|
||||
if (argbuf != NULL && argbuf != buf) {
|
||||
continue;
|
||||
}
|
||||
if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
|
||||
|| (sel_buflisted && !buf->b_p_bl)
|
||||
|| (sel_bufmodified && !buf->b_changed))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dict_T *const d = get_buffer_info(buf);
|
||||
tv_list_append_dict(rettv->vval.v_list, d);
|
||||
if (argbuf != NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get line or list of lines from buffer "buf" into "rettv".
|
||||
///
|
||||
/// @param retlist if true, then the lines are returned as a Vim List.
|
||||
///
|
||||
/// @return range (from start to end) of lines in rettv from the specified
|
||||
/// buffer.
|
||||
static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv)
|
||||
{
|
||||
rettv->v_type = (retlist ? VAR_LIST : VAR_STRING);
|
||||
rettv->vval.v_string = NULL;
|
||||
|
||||
if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0 || end < start) {
|
||||
if (retlist) {
|
||||
tv_list_alloc_ret(rettv, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (retlist) {
|
||||
if (start < 1) {
|
||||
start = 1;
|
||||
}
|
||||
if (end > buf->b_ml.ml_line_count) {
|
||||
end = buf->b_ml.ml_line_count;
|
||||
}
|
||||
tv_list_alloc_ret(rettv, end - start + 1);
|
||||
while (start <= end) {
|
||||
tv_list_append_string(rettv->vval.v_list,
|
||||
(const char *)ml_get_buf(buf, start++, false), -1);
|
||||
}
|
||||
} else {
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = ((start >= 1 && start <= buf->b_ml.ml_line_count)
|
||||
? xstrdup(ml_get_buf(buf, start, false)) : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/// @param retlist true: "getbufline()" function
|
||||
/// false: "getbufoneline()" function
|
||||
static void getbufline(typval_T *argvars, typval_T *rettv, bool retlist)
|
||||
{
|
||||
const int did_emsg_before = did_emsg;
|
||||
buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
|
||||
const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
|
||||
if (did_emsg > did_emsg_before) {
|
||||
return;
|
||||
}
|
||||
const linenr_T end = (argvars[2].v_type == VAR_UNKNOWN
|
||||
? lnum
|
||||
: tv_get_lnum_buf(&argvars[2], buf));
|
||||
|
||||
get_buffer_lines(buf, lnum, end, retlist, rettv);
|
||||
}
|
||||
|
||||
/// "getbufline()" function
|
||||
void f_getbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
getbufline(argvars, rettv, true);
|
||||
}
|
||||
|
||||
/// "getbufoneline()" function
|
||||
void f_getbufoneline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
getbufline(argvars, rettv, false);
|
||||
}
|
||||
|
||||
/// "getline(lnum, [end])" function
|
||||
void f_getline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
linenr_T end;
|
||||
bool retlist;
|
||||
|
||||
const linenr_T lnum = tv_get_lnum(argvars);
|
||||
if (argvars[1].v_type == VAR_UNKNOWN) {
|
||||
end = lnum;
|
||||
retlist = false;
|
||||
} else {
|
||||
end = tv_get_lnum(&argvars[1]);
|
||||
retlist = true;
|
||||
}
|
||||
|
||||
get_buffer_lines(curbuf, lnum, end, retlist, rettv);
|
||||
}
|
||||
|
||||
/// "setbufline()" function
|
||||
void f_setbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
buf_set_append_line(argvars, rettv, false);
|
||||
}
|
||||
|
||||
/// "setline()" function
|
||||
void f_setline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
const int did_emsg_before = did_emsg;
|
||||
linenr_T lnum = tv_get_lnum(&argvars[0]);
|
||||
if (did_emsg == did_emsg_before) {
|
||||
set_buffer_lines(curbuf, lnum, false, &argvars[1], rettv);
|
||||
}
|
||||
}
|
||||
|
||||
/// Make "buf" the current buffer.
|
||||
///
|
||||
/// restore_buffer() MUST be called to undo.
|
||||
/// No autocommands will be executed. Use aucmd_prepbuf() if there are any.
|
||||
void switch_buffer(bufref_T *save_curbuf, buf_T *buf)
|
||||
{
|
||||
block_autocmds();
|
||||
set_bufref(save_curbuf, curbuf);
|
||||
curbuf->b_nwindows--;
|
||||
curbuf = buf;
|
||||
curwin->w_buffer = buf;
|
||||
curbuf->b_nwindows++;
|
||||
}
|
||||
|
||||
/// Restore the current buffer after using switch_buffer().
|
||||
void restore_buffer(bufref_T *save_curbuf)
|
||||
{
|
||||
unblock_autocmds();
|
||||
// Check for valid buffer, just in case.
|
||||
if (bufref_valid(save_curbuf)) {
|
||||
curbuf->b_nwindows--;
|
||||
curwin->w_buffer = save_curbuf->br_buf;
|
||||
curbuf = save_curbuf->br_buf;
|
||||
curbuf->b_nwindows++;
|
||||
}
|
||||
}
|
||||
|
||||
/// Find a window for buffer "buf".
|
||||
/// If found true is returned and "wp" and "tp" are set to
|
||||
/// the window and tabpage.
|
||||
/// If not found, false is returned.
|
||||
///
|
||||
/// @param buf buffer to find a window for
|
||||
/// @param[out] wp stores the found window
|
||||
/// @param[out] tp stores the found tabpage
|
||||
///
|
||||
/// @return true if a window was found for the buffer.
|
||||
bool find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp)
|
||||
{
|
||||
*wp = NULL;
|
||||
*tp = NULL;
|
||||
FOR_ALL_TAB_WINDOWS(tp2, wp2) {
|
||||
if (wp2->w_buffer == buf) {
|
||||
*tp = tp2;
|
||||
*wp = wp2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
10
src/nvim/eval/buffer.h
Normal file
10
src/nvim/eval/buffer.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef NVIM_EVAL_BUFFER_H
|
||||
#define NVIM_EVAL_BUFFER_H
|
||||
|
||||
#include "nvim/buffer_defs.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "eval/buffer.h.generated.h"
|
||||
#endif
|
||||
#endif // NVIM_EVAL_BUFFER_H
|
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,7 @@
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/eval/userfunc.h"
|
||||
#include "nvim/eval/vars.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/ex_cmds.h"
|
||||
#include "nvim/ex_cmds_defs.h"
|
||||
#include "nvim/ex_docmd.h"
|
||||
|
945
src/nvim/eval/window.c
Normal file
945
src/nvim/eval/window.c
Normal file
@ -0,0 +1,945 @@
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
||||
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
// eval/window.c: Window related builtin functions
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nvim/ascii.h"
|
||||
#include "nvim/autocmd.h"
|
||||
#include "nvim/buffer.h"
|
||||
#include "nvim/cursor.h"
|
||||
#include "nvim/eval/funcs.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/garray.h"
|
||||
#include "nvim/gettext.h"
|
||||
#include "nvim/globals.h"
|
||||
#include "nvim/macros.h"
|
||||
#include "nvim/memline_defs.h"
|
||||
#include "nvim/memory.h"
|
||||
#include "nvim/message.h"
|
||||
#include "nvim/move.h"
|
||||
#include "nvim/option_defs.h"
|
||||
#include "nvim/pos.h"
|
||||
#include "nvim/types.h"
|
||||
#include "nvim/vim.h"
|
||||
#include "nvim/window.h"
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "eval/window.c.generated.h"
|
||||
#endif
|
||||
|
||||
static char *e_invalwindow = N_("E957: Invalid window number");
|
||||
static char e_cannot_resize_window_in_another_tab_page[]
|
||||
= N_("E1308: Cannot resize a window in another tab page");
|
||||
|
||||
static int win_getid(typval_T *argvars)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_UNKNOWN) {
|
||||
return curwin->handle;
|
||||
}
|
||||
int winnr = (int)tv_get_number(&argvars[0]);
|
||||
win_T *wp;
|
||||
if (winnr > 0) {
|
||||
if (argvars[1].v_type == VAR_UNKNOWN) {
|
||||
wp = firstwin;
|
||||
} else {
|
||||
tabpage_T *tp = NULL;
|
||||
int tabnr = (int)tv_get_number(&argvars[1]);
|
||||
FOR_ALL_TABS(tp2) {
|
||||
if (--tabnr == 0) {
|
||||
tp = tp2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (tp == curtab) {
|
||||
wp = firstwin;
|
||||
} else {
|
||||
wp = tp->tp_firstwin;
|
||||
}
|
||||
}
|
||||
for (; wp != NULL; wp = wp->w_next) {
|
||||
if (--winnr == 0) {
|
||||
return wp->handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void win_id2tabwin(typval_T *const argvars, typval_T *const rettv)
|
||||
{
|
||||
handle_T id = (handle_T)tv_get_number(&argvars[0]);
|
||||
|
||||
int winnr = 1;
|
||||
int tabnr = 1;
|
||||
win_get_tabwin(id, &tabnr, &winnr);
|
||||
|
||||
list_T *const list = tv_list_alloc_ret(rettv, 2);
|
||||
tv_list_append_number(list, tabnr);
|
||||
tv_list_append_number(list, winnr);
|
||||
}
|
||||
|
||||
win_T *win_id2wp(int id)
|
||||
{
|
||||
return win_id2wp_tp(id, NULL);
|
||||
}
|
||||
|
||||
/// Return the window and tab pointer of window "id".
|
||||
win_T *win_id2wp_tp(int id, tabpage_T **tpp)
|
||||
{
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (wp->handle == id) {
|
||||
if (tpp != NULL) {
|
||||
*tpp = tp;
|
||||
}
|
||||
return wp;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int win_id2win(typval_T *argvars)
|
||||
{
|
||||
int nr = 1;
|
||||
int id = (int)tv_get_number(&argvars[0]);
|
||||
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->handle == id) {
|
||||
return nr;
|
||||
}
|
||||
nr++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void win_findbuf(typval_T *argvars, list_T *list)
|
||||
{
|
||||
int bufnr = (int)tv_get_number(&argvars[0]);
|
||||
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (wp->w_buffer->b_fnum == bufnr) {
|
||||
tv_list_append_number(list, wp->handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Find window specified by "vp" in tabpage "tp".
|
||||
///
|
||||
/// @param tp NULL for current tab page
|
||||
win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp)
|
||||
{
|
||||
int nr = (int)tv_get_number_chk(vp, NULL);
|
||||
|
||||
if (nr < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nr == 0) {
|
||||
return curwin;
|
||||
}
|
||||
|
||||
// This method accepts NULL as an alias for curtab.
|
||||
if (tp == NULL) {
|
||||
tp = curtab;
|
||||
}
|
||||
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
|
||||
if (nr >= LOWEST_WIN_ID) {
|
||||
if (wp->handle == nr) {
|
||||
return wp;
|
||||
}
|
||||
} else if (--nr <= 0) {
|
||||
return wp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Find a window: When using a Window ID in any tab page, when using a number
|
||||
/// in the current tab page.
|
||||
win_T *find_win_by_nr_or_id(typval_T *vp)
|
||||
{
|
||||
int nr = (int)tv_get_number_chk(vp, NULL);
|
||||
|
||||
if (nr >= LOWEST_WIN_ID) {
|
||||
return win_id2wp((int)tv_get_number(vp));
|
||||
}
|
||||
|
||||
return find_win_by_nr(vp, NULL);
|
||||
}
|
||||
|
||||
/// Find window specified by "wvp" in tabpage "tvp".
|
||||
win_T *find_tabwin(typval_T *wvp, typval_T *tvp)
|
||||
{
|
||||
win_T *wp = NULL;
|
||||
tabpage_T *tp = NULL;
|
||||
|
||||
if (wvp->v_type != VAR_UNKNOWN) {
|
||||
if (tvp->v_type != VAR_UNKNOWN) {
|
||||
long n = tv_get_number(tvp);
|
||||
if (n >= 0) {
|
||||
tp = find_tabpage((int)n);
|
||||
}
|
||||
} else {
|
||||
tp = curtab;
|
||||
}
|
||||
|
||||
if (tp != NULL) {
|
||||
wp = find_win_by_nr(wvp, tp);
|
||||
}
|
||||
} else {
|
||||
wp = curwin;
|
||||
}
|
||||
|
||||
return wp;
|
||||
}
|
||||
|
||||
/// Get the layout of the given tab page for winlayout().
|
||||
static void get_framelayout(const frame_T *fr, list_T *l, bool outer)
|
||||
{
|
||||
if (fr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
list_T *fr_list;
|
||||
if (outer) {
|
||||
// outermost call from f_winlayout()
|
||||
fr_list = l;
|
||||
} else {
|
||||
fr_list = tv_list_alloc(2);
|
||||
tv_list_append_list(l, fr_list);
|
||||
}
|
||||
|
||||
if (fr->fr_layout == FR_LEAF) {
|
||||
if (fr->fr_win != NULL) {
|
||||
tv_list_append_string(fr_list, "leaf", -1);
|
||||
tv_list_append_number(fr_list, fr->fr_win->handle);
|
||||
}
|
||||
} else {
|
||||
tv_list_append_string(fr_list, fr->fr_layout == FR_ROW ? "row" : "col", -1);
|
||||
|
||||
list_T *const win_list = tv_list_alloc(kListLenUnknown);
|
||||
tv_list_append_list(fr_list, win_list);
|
||||
const frame_T *child = fr->fr_child;
|
||||
while (child != NULL) {
|
||||
get_framelayout(child, win_list, false);
|
||||
child = child->fr_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Common code for tabpagewinnr() and winnr().
|
||||
static int get_winnr(tabpage_T *tp, typval_T *argvar)
|
||||
{
|
||||
int nr = 1;
|
||||
|
||||
win_T *twin = (tp == curtab) ? curwin : tp->tp_curwin;
|
||||
if (argvar->v_type != VAR_UNKNOWN) {
|
||||
bool invalid_arg = false;
|
||||
const char *const arg = tv_get_string_chk(argvar);
|
||||
if (arg == NULL) {
|
||||
nr = 0; // Type error; errmsg already given.
|
||||
} else if (strcmp(arg, "$") == 0) {
|
||||
twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
|
||||
} else if (strcmp(arg, "#") == 0) {
|
||||
twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
|
||||
if (twin == NULL) {
|
||||
nr = 0;
|
||||
}
|
||||
} else {
|
||||
// Extract the window count (if specified). e.g. winnr('3j')
|
||||
char *endp;
|
||||
long count = strtol((char *)arg, &endp, 10);
|
||||
if (count <= 0) {
|
||||
// if count is not specified, default to 1
|
||||
count = 1;
|
||||
}
|
||||
if (endp != NULL && *endp != '\0') {
|
||||
if (strequal(endp, "j")) {
|
||||
twin = win_vert_neighbor(tp, twin, false, count);
|
||||
} else if (strequal(endp, "k")) {
|
||||
twin = win_vert_neighbor(tp, twin, true, count);
|
||||
} else if (strequal(endp, "h")) {
|
||||
twin = win_horz_neighbor(tp, twin, true, count);
|
||||
} else if (strequal(endp, "l")) {
|
||||
twin = win_horz_neighbor(tp, twin, false, count);
|
||||
} else {
|
||||
invalid_arg = true;
|
||||
}
|
||||
} else {
|
||||
invalid_arg = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (invalid_arg) {
|
||||
semsg(_(e_invexpr2), arg);
|
||||
nr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (nr > 0) {
|
||||
for (win_T *wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
|
||||
wp != twin; wp = wp->w_next) {
|
||||
if (wp == NULL) {
|
||||
// didn't find it in this tabpage
|
||||
nr = 0;
|
||||
break;
|
||||
}
|
||||
nr++;
|
||||
}
|
||||
}
|
||||
return nr;
|
||||
}
|
||||
|
||||
/// @return information about a window as a dictionary.
|
||||
static dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
|
||||
{
|
||||
dict_T *const dict = tv_dict_alloc();
|
||||
|
||||
// make sure w_botline is valid
|
||||
validate_botline(wp);
|
||||
|
||||
tv_dict_add_nr(dict, S_LEN("tabnr"), tpnr);
|
||||
tv_dict_add_nr(dict, S_LEN("winnr"), winnr);
|
||||
tv_dict_add_nr(dict, S_LEN("winid"), wp->handle);
|
||||
tv_dict_add_nr(dict, S_LEN("height"), wp->w_height_inner);
|
||||
tv_dict_add_nr(dict, S_LEN("winrow"), wp->w_winrow + 1);
|
||||
tv_dict_add_nr(dict, S_LEN("topline"), wp->w_topline);
|
||||
tv_dict_add_nr(dict, S_LEN("botline"), wp->w_botline - 1);
|
||||
tv_dict_add_nr(dict, S_LEN("winbar"), wp->w_winbar_height);
|
||||
tv_dict_add_nr(dict, S_LEN("width"), wp->w_width_inner);
|
||||
tv_dict_add_nr(dict, S_LEN("bufnr"), wp->w_buffer->b_fnum);
|
||||
tv_dict_add_nr(dict, S_LEN("wincol"), wp->w_wincol + 1);
|
||||
tv_dict_add_nr(dict, S_LEN("textoff"), win_col_off(wp));
|
||||
tv_dict_add_nr(dict, S_LEN("terminal"), bt_terminal(wp->w_buffer));
|
||||
tv_dict_add_nr(dict, S_LEN("quickfix"), bt_quickfix(wp->w_buffer));
|
||||
tv_dict_add_nr(dict, S_LEN("loclist"),
|
||||
(bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
|
||||
|
||||
// Add a reference to window variables
|
||||
tv_dict_add_dict(dict, S_LEN("variables"), wp->w_vars);
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
/// @return information (variables, options, etc.) about a tab page
|
||||
/// as a dictionary.
|
||||
static dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx)
|
||||
{
|
||||
dict_T *const dict = tv_dict_alloc();
|
||||
|
||||
tv_dict_add_nr(dict, S_LEN("tabnr"), tp_idx);
|
||||
|
||||
list_T *const l = tv_list_alloc(kListLenMayKnow);
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
|
||||
tv_list_append_number(l, (varnumber_T)wp->handle);
|
||||
}
|
||||
tv_dict_add_list(dict, S_LEN("windows"), l);
|
||||
|
||||
// Make a reference to tabpage variables
|
||||
tv_dict_add_dict(dict, S_LEN("variables"), tp->tp_vars);
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
/// "gettabinfo()" function
|
||||
void f_gettabinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
tabpage_T *tparg = NULL;
|
||||
|
||||
tv_list_alloc_ret(rettv, (argvars[0].v_type == VAR_UNKNOWN
|
||||
? 1
|
||||
: kListLenMayKnow));
|
||||
|
||||
if (argvars[0].v_type != VAR_UNKNOWN) {
|
||||
// Information about one tab page
|
||||
tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
|
||||
if (tparg == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get information about a specific tab page or all tab pages
|
||||
int tpnr = 0;
|
||||
FOR_ALL_TABS(tp) {
|
||||
tpnr++;
|
||||
if (tparg != NULL && tp != tparg) {
|
||||
continue;
|
||||
}
|
||||
dict_T *const d = get_tabpage_info(tp, tpnr);
|
||||
tv_list_append_dict(rettv->vval.v_list, d);
|
||||
if (tparg != NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// "getwininfo()" function
|
||||
void f_getwininfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
win_T *wparg = NULL;
|
||||
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
|
||||
if (argvars[0].v_type != VAR_UNKNOWN) {
|
||||
wparg = win_id2wp((int)tv_get_number(&argvars[0]));
|
||||
if (wparg == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect information about either all the windows across all the tab
|
||||
// pages or one particular window.
|
||||
int16_t tabnr = 0;
|
||||
FOR_ALL_TABS(tp) {
|
||||
tabnr++;
|
||||
int16_t winnr = 0;
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
|
||||
winnr++;
|
||||
if (wparg != NULL && wp != wparg) {
|
||||
continue;
|
||||
}
|
||||
dict_T *const d = get_win_info(wp, tabnr, winnr);
|
||||
tv_list_append_dict(rettv->vval.v_list, d);
|
||||
if (wparg != NULL) {
|
||||
// found information about a specific window
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// "getwinpos({timeout})" function
|
||||
void f_getwinpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
tv_list_alloc_ret(rettv, 2);
|
||||
tv_list_append_number(rettv->vval.v_list, -1);
|
||||
tv_list_append_number(rettv->vval.v_list, -1);
|
||||
}
|
||||
|
||||
/// "getwinposx()" function
|
||||
void f_getwinposx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
rettv->vval.v_number = -1;
|
||||
}
|
||||
|
||||
/// "getwinposy()" function
|
||||
void f_getwinposy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
rettv->vval.v_number = -1;
|
||||
}
|
||||
|
||||
/// "tabpagenr()" function
|
||||
void f_tabpagenr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
int nr = 1;
|
||||
|
||||
if (argvars[0].v_type != VAR_UNKNOWN) {
|
||||
const char *const arg = tv_get_string_chk(&argvars[0]);
|
||||
nr = 0;
|
||||
if (arg != NULL) {
|
||||
if (strcmp(arg, "$") == 0) {
|
||||
nr = tabpage_index(NULL) - 1;
|
||||
} else if (strcmp(arg, "#") == 0) {
|
||||
nr = valid_tabpage(lastused_tabpage) ? tabpage_index(lastused_tabpage) : 0;
|
||||
} else {
|
||||
semsg(_(e_invexpr2), arg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nr = tabpage_index(curtab);
|
||||
}
|
||||
rettv->vval.v_number = nr;
|
||||
}
|
||||
|
||||
/// "tabpagewinnr()" function
|
||||
void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
int nr = 1;
|
||||
tabpage_T *const tp = find_tabpage((int)tv_get_number(&argvars[0]));
|
||||
if (tp == NULL) {
|
||||
nr = 0;
|
||||
} else {
|
||||
nr = get_winnr(tp, &argvars[1]);
|
||||
}
|
||||
rettv->vval.v_number = nr;
|
||||
}
|
||||
|
||||
/// "win_execute(win_id, command)" function
|
||||
void f_win_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
// Return an empty string if something fails.
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
|
||||
int id = (int)tv_get_number(argvars);
|
||||
tabpage_T *tp;
|
||||
win_T *wp = win_id2wp_tp(id, &tp);
|
||||
if (wp != NULL && tp != NULL) {
|
||||
WIN_EXECUTE(wp, tp, execute_common(argvars, rettv, 1));
|
||||
}
|
||||
}
|
||||
|
||||
/// "win_findbuf()" function
|
||||
void f_win_findbuf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
win_findbuf(argvars, rettv->vval.v_list);
|
||||
}
|
||||
|
||||
/// "win_getid()" function
|
||||
void f_win_getid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
rettv->vval.v_number = win_getid(argvars);
|
||||
}
|
||||
|
||||
/// "win_gotoid()" function
|
||||
void f_win_gotoid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
int id = (int)tv_get_number(&argvars[0]);
|
||||
|
||||
if (cmdwin_type != 0) {
|
||||
emsg(_(e_cmdwin));
|
||||
return;
|
||||
}
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (wp->handle == id) {
|
||||
goto_tabpage_win(tp, wp);
|
||||
rettv->vval.v_number = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// "win_id2tabwin()" function
|
||||
void f_win_id2tabwin(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
win_id2tabwin(argvars, rettv);
|
||||
}
|
||||
|
||||
/// "win_id2win()" function
|
||||
void f_win_id2win(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
rettv->vval.v_number = win_id2win(argvars);
|
||||
}
|
||||
|
||||
/// "win_move_separator()" function
|
||||
void f_win_move_separator(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
rettv->vval.v_number = false;
|
||||
|
||||
win_T *wp = find_win_by_nr_or_id(&argvars[0]);
|
||||
if (wp == NULL || wp->w_floating) {
|
||||
return;
|
||||
}
|
||||
if (!win_valid(wp)) {
|
||||
emsg(_(e_cannot_resize_window_in_another_tab_page));
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = (int)tv_get_number(&argvars[1]);
|
||||
win_drag_vsep_line(wp, offset);
|
||||
rettv->vval.v_number = true;
|
||||
}
|
||||
|
||||
/// "win_move_statusline()" function
|
||||
void f_win_move_statusline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
win_T *wp;
|
||||
int offset;
|
||||
|
||||
rettv->vval.v_number = false;
|
||||
|
||||
wp = find_win_by_nr_or_id(&argvars[0]);
|
||||
if (wp == NULL || wp->w_floating) {
|
||||
return;
|
||||
}
|
||||
if (!win_valid(wp)) {
|
||||
emsg(_(e_cannot_resize_window_in_another_tab_page));
|
||||
return;
|
||||
}
|
||||
|
||||
offset = (int)tv_get_number(&argvars[1]);
|
||||
win_drag_status_line(wp, offset);
|
||||
rettv->vval.v_number = true;
|
||||
}
|
||||
|
||||
/// "win_screenpos()" function
|
||||
void f_win_screenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
tv_list_alloc_ret(rettv, 2);
|
||||
const win_T *const wp = find_win_by_nr_or_id(&argvars[0]);
|
||||
tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
|
||||
tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
|
||||
}
|
||||
|
||||
/// Move the window wp into a new split of targetwin in a given direction
|
||||
static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
|
||||
{
|
||||
int height = wp->w_height;
|
||||
win_T *oldwin = curwin;
|
||||
|
||||
if (wp == targetwin || wp == aucmd_win) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Jump to the target window
|
||||
if (curwin != targetwin) {
|
||||
win_goto(targetwin);
|
||||
}
|
||||
|
||||
// Remove the old window and frame from the tree of frames
|
||||
int dir;
|
||||
(void)winframe_remove(wp, &dir, NULL);
|
||||
win_remove(wp, NULL);
|
||||
last_status(false); // may need to remove last status line
|
||||
(void)win_comp_pos(); // recompute window positions
|
||||
|
||||
// Split a window on the desired side and put the old window there
|
||||
(void)win_split_ins(size, flags, wp, dir);
|
||||
|
||||
// If splitting horizontally, try to preserve height
|
||||
if (size == 0 && !(flags & WSP_VERT)) {
|
||||
win_setheight_win(height, wp);
|
||||
if (p_ea) {
|
||||
win_equal(wp, true, 'v');
|
||||
}
|
||||
}
|
||||
|
||||
if (oldwin != curwin) {
|
||||
win_goto(oldwin);
|
||||
}
|
||||
}
|
||||
|
||||
/// "win_splitmove()" function
|
||||
void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
win_T *wp = find_win_by_nr_or_id(&argvars[0]);
|
||||
win_T *targetwin = find_win_by_nr_or_id(&argvars[1]);
|
||||
|
||||
if (wp == NULL || targetwin == NULL || wp == targetwin
|
||||
|| !win_valid(wp) || !win_valid(targetwin)
|
||||
|| win_valid_floating(wp) || win_valid_floating(targetwin)) {
|
||||
emsg(_(e_invalwindow));
|
||||
rettv->vval.v_number = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int flags = 0, size = 0;
|
||||
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
dict_T *d;
|
||||
dictitem_T *di;
|
||||
|
||||
if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL) {
|
||||
emsg(_(e_invarg));
|
||||
return;
|
||||
}
|
||||
|
||||
d = argvars[2].vval.v_dict;
|
||||
if (tv_dict_get_number(d, "vertical")) {
|
||||
flags |= WSP_VERT;
|
||||
}
|
||||
if ((di = tv_dict_find(d, "rightbelow", -1)) != NULL) {
|
||||
flags |= tv_get_number(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
|
||||
}
|
||||
size = (int)tv_dict_get_number(d, "size");
|
||||
}
|
||||
|
||||
win_move_into_split(wp, targetwin, size, flags);
|
||||
}
|
||||
|
||||
/// "win_gettype(nr)" function
|
||||
void f_win_gettype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
win_T *wp = curwin;
|
||||
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
if (argvars[0].v_type != VAR_UNKNOWN) {
|
||||
wp = find_win_by_nr_or_id(&argvars[0]);
|
||||
if (wp == NULL) {
|
||||
rettv->vval.v_string = xstrdup("unknown");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (wp == aucmd_win) {
|
||||
rettv->vval.v_string = xstrdup("autocmd");
|
||||
} else if (wp->w_p_pvw) {
|
||||
rettv->vval.v_string = xstrdup("preview");
|
||||
} else if (wp->w_floating) {
|
||||
rettv->vval.v_string = xstrdup("popup");
|
||||
} else if (wp == curwin && cmdwin_type != 0) {
|
||||
rettv->vval.v_string = xstrdup("command");
|
||||
} else if (bt_quickfix(wp->w_buffer)) {
|
||||
rettv->vval.v_string = xstrdup((wp->w_llist_ref != NULL ? "loclist" : "quickfix"));
|
||||
}
|
||||
}
|
||||
|
||||
/// "getcmdwintype()" function
|
||||
void f_getcmdwintype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
rettv->vval.v_string = xmallocz(1);
|
||||
rettv->vval.v_string[0] = (char)cmdwin_type;
|
||||
}
|
||||
|
||||
/// "winbufnr(nr)" function
|
||||
void f_winbufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
win_T *wp = find_win_by_nr_or_id(&argvars[0]);
|
||||
if (wp == NULL) {
|
||||
rettv->vval.v_number = -1;
|
||||
} else {
|
||||
rettv->vval.v_number = wp->w_buffer->b_fnum;
|
||||
}
|
||||
}
|
||||
|
||||
/// "wincol()" function
|
||||
void f_wincol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
validate_cursor();
|
||||
rettv->vval.v_number = curwin->w_wcol + 1;
|
||||
}
|
||||
|
||||
/// "winheight(nr)" function
|
||||
void f_winheight(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
win_T *wp = find_win_by_nr_or_id(&argvars[0]);
|
||||
if (wp == NULL) {
|
||||
rettv->vval.v_number = -1;
|
||||
} else {
|
||||
rettv->vval.v_number = wp->w_height_inner;
|
||||
}
|
||||
}
|
||||
|
||||
/// "winlayout()" function
|
||||
void f_winlayout(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
tabpage_T *tp;
|
||||
|
||||
tv_list_alloc_ret(rettv, 2);
|
||||
|
||||
if (argvars[0].v_type == VAR_UNKNOWN) {
|
||||
tp = curtab;
|
||||
} else {
|
||||
tp = find_tabpage((int)tv_get_number(&argvars[0]));
|
||||
if (tp == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
get_framelayout(tp->tp_topframe, rettv->vval.v_list, true);
|
||||
}
|
||||
|
||||
/// "winline()" function
|
||||
void f_winline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
validate_cursor();
|
||||
rettv->vval.v_number = curwin->w_wrow + 1;
|
||||
}
|
||||
|
||||
/// "winnr()" function
|
||||
void f_winnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
rettv->vval.v_number = get_winnr(curtab, &argvars[0]);
|
||||
}
|
||||
|
||||
/// "winrestcmd()" function
|
||||
void f_winrestcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
char_u buf[50];
|
||||
|
||||
garray_T ga;
|
||||
ga_init(&ga, (int)sizeof(char), 70);
|
||||
|
||||
// Do this twice to handle some window layouts properly.
|
||||
for (int i = 0; i < 2; i++) {
|
||||
int winnr = 1;
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
snprintf((char *)buf, sizeof(buf), "%dresize %d|", winnr,
|
||||
wp->w_height);
|
||||
ga_concat(&ga, (char *)buf);
|
||||
snprintf((char *)buf, sizeof(buf), "vert %dresize %d|", winnr,
|
||||
wp->w_width);
|
||||
ga_concat(&ga, (char *)buf);
|
||||
winnr++;
|
||||
}
|
||||
}
|
||||
ga_append(&ga, NUL);
|
||||
|
||||
rettv->vval.v_string = ga.ga_data;
|
||||
rettv->v_type = VAR_STRING;
|
||||
}
|
||||
|
||||
/// "winrestview()" function
|
||||
void f_winrestview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
dict_T *dict = argvars[0].vval.v_dict;
|
||||
|
||||
if (argvars[0].v_type != VAR_DICT || dict == NULL) {
|
||||
emsg(_(e_invarg));
|
||||
} else {
|
||||
dictitem_T *di;
|
||||
if ((di = tv_dict_find(dict, S_LEN("lnum"))) != NULL) {
|
||||
curwin->w_cursor.lnum = (linenr_T)tv_get_number(&di->di_tv);
|
||||
}
|
||||
if ((di = tv_dict_find(dict, S_LEN("col"))) != NULL) {
|
||||
curwin->w_cursor.col = (colnr_T)tv_get_number(&di->di_tv);
|
||||
}
|
||||
if ((di = tv_dict_find(dict, S_LEN("coladd"))) != NULL) {
|
||||
curwin->w_cursor.coladd = (colnr_T)tv_get_number(&di->di_tv);
|
||||
}
|
||||
if ((di = tv_dict_find(dict, S_LEN("curswant"))) != NULL) {
|
||||
curwin->w_curswant = (colnr_T)tv_get_number(&di->di_tv);
|
||||
curwin->w_set_curswant = false;
|
||||
}
|
||||
if ((di = tv_dict_find(dict, S_LEN("topline"))) != NULL) {
|
||||
set_topline(curwin, (linenr_T)tv_get_number(&di->di_tv));
|
||||
}
|
||||
if ((di = tv_dict_find(dict, S_LEN("topfill"))) != NULL) {
|
||||
curwin->w_topfill = (int)tv_get_number(&di->di_tv);
|
||||
}
|
||||
if ((di = tv_dict_find(dict, S_LEN("leftcol"))) != NULL) {
|
||||
curwin->w_leftcol = (colnr_T)tv_get_number(&di->di_tv);
|
||||
}
|
||||
if ((di = tv_dict_find(dict, S_LEN("skipcol"))) != NULL) {
|
||||
curwin->w_skipcol = (colnr_T)tv_get_number(&di->di_tv);
|
||||
}
|
||||
|
||||
check_cursor();
|
||||
win_new_height(curwin, curwin->w_height);
|
||||
win_new_width(curwin, curwin->w_width);
|
||||
changed_window_setting();
|
||||
|
||||
if (curwin->w_topline <= 0) {
|
||||
curwin->w_topline = 1;
|
||||
}
|
||||
if (curwin->w_topline > curbuf->b_ml.ml_line_count) {
|
||||
curwin->w_topline = curbuf->b_ml.ml_line_count;
|
||||
}
|
||||
check_topfill(curwin, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// "winsaveview()" function
|
||||
void f_winsaveview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
tv_dict_alloc_ret(rettv);
|
||||
dict_T *dict = rettv->vval.v_dict;
|
||||
|
||||
tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)curwin->w_cursor.lnum);
|
||||
tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)curwin->w_cursor.col);
|
||||
tv_dict_add_nr(dict, S_LEN("coladd"), (varnumber_T)curwin->w_cursor.coladd);
|
||||
update_curswant();
|
||||
tv_dict_add_nr(dict, S_LEN("curswant"), (varnumber_T)curwin->w_curswant);
|
||||
|
||||
tv_dict_add_nr(dict, S_LEN("topline"), (varnumber_T)curwin->w_topline);
|
||||
tv_dict_add_nr(dict, S_LEN("topfill"), (varnumber_T)curwin->w_topfill);
|
||||
tv_dict_add_nr(dict, S_LEN("leftcol"), (varnumber_T)curwin->w_leftcol);
|
||||
tv_dict_add_nr(dict, S_LEN("skipcol"), (varnumber_T)curwin->w_skipcol);
|
||||
}
|
||||
|
||||
/// "winwidth(nr)" function
|
||||
void f_winwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
win_T *wp = find_win_by_nr_or_id(&argvars[0]);
|
||||
if (wp == NULL) {
|
||||
rettv->vval.v_number = -1;
|
||||
} else {
|
||||
rettv->vval.v_number = wp->w_width_inner;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set "win" to be the curwin and "tp" to be the current tab page.
|
||||
/// restore_win() MUST be called to undo, also when FAIL is returned.
|
||||
/// No autocommands will be executed until restore_win() is called.
|
||||
///
|
||||
/// @param no_display if true the display won't be affected, no redraw is
|
||||
/// triggered, another tabpage access is limited.
|
||||
///
|
||||
/// @return FAIL if switching to "win" failed.
|
||||
int switch_win(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display)
|
||||
{
|
||||
block_autocmds();
|
||||
return switch_win_noblock(switchwin, win, tp, no_display);
|
||||
}
|
||||
|
||||
// As switch_win() but without blocking autocommands.
|
||||
int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display)
|
||||
{
|
||||
CLEAR_POINTER(switchwin);
|
||||
switchwin->sw_curwin = curwin;
|
||||
if (win == curwin) {
|
||||
switchwin->sw_same_win = true;
|
||||
} else {
|
||||
// Disable Visual selection, because redrawing may fail.
|
||||
switchwin->sw_visual_active = VIsual_active;
|
||||
VIsual_active = false;
|
||||
}
|
||||
|
||||
if (tp != NULL) {
|
||||
switchwin->sw_curtab = curtab;
|
||||
if (no_display) {
|
||||
curtab->tp_firstwin = firstwin;
|
||||
curtab->tp_lastwin = lastwin;
|
||||
curtab = tp;
|
||||
firstwin = curtab->tp_firstwin;
|
||||
lastwin = curtab->tp_lastwin;
|
||||
} else {
|
||||
goto_tabpage_tp(tp, false, false);
|
||||
}
|
||||
}
|
||||
if (!win_valid(win)) {
|
||||
return FAIL;
|
||||
}
|
||||
curwin = win;
|
||||
curbuf = curwin->w_buffer;
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Restore current tabpage and window saved by switch_win(), if still valid.
|
||||
// When "no_display" is true the display won't be affected, no redraw is
|
||||
// triggered.
|
||||
void restore_win(switchwin_T *switchwin, bool no_display)
|
||||
{
|
||||
restore_win_noblock(switchwin, no_display);
|
||||
unblock_autocmds();
|
||||
}
|
||||
|
||||
// As restore_win() but without unblocking autocommands.
|
||||
void restore_win_noblock(switchwin_T *switchwin, bool no_display)
|
||||
{
|
||||
if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab)) {
|
||||
if (no_display) {
|
||||
curtab->tp_firstwin = firstwin;
|
||||
curtab->tp_lastwin = lastwin;
|
||||
curtab = switchwin->sw_curtab;
|
||||
firstwin = curtab->tp_firstwin;
|
||||
lastwin = curtab->tp_lastwin;
|
||||
} else {
|
||||
goto_tabpage_tp(switchwin->sw_curtab, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!switchwin->sw_same_win) {
|
||||
VIsual_active = switchwin->sw_visual_active;
|
||||
}
|
||||
|
||||
if (win_valid(switchwin->sw_curwin)) {
|
||||
curwin = switchwin->sw_curwin;
|
||||
curbuf = curwin->w_buffer;
|
||||
}
|
||||
}
|
68
src/nvim/eval/window.h
Normal file
68
src/nvim/eval/window.h
Normal file
@ -0,0 +1,68 @@
|
||||
#ifndef NVIM_EVAL_WINDOW_H
|
||||
#define NVIM_EVAL_WINDOW_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "nvim/buffer_defs.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
|
||||
/// Structure used by switch_win() to pass values to restore_win()
|
||||
typedef struct {
|
||||
win_T *sw_curwin;
|
||||
tabpage_T *sw_curtab;
|
||||
bool sw_same_win; ///< VIsual_active was not reset
|
||||
bool sw_visual_active;
|
||||
} switchwin_T;
|
||||
|
||||
/// Execute a block of code in the context of window `wp` in tabpage `tp`.
|
||||
/// Ensures the status line is redrawn and cursor position is valid if it is moved.
|
||||
#define WIN_EXECUTE(wp, tp, block) \
|
||||
do { \
|
||||
win_T *const wp_ = (wp); \
|
||||
const pos_T curpos_ = wp_->w_cursor; \
|
||||
char cwd_[MAXPATHL]; \
|
||||
char autocwd_[MAXPATHL]; \
|
||||
bool apply_acd_ = false; \
|
||||
int cwd_status_ = FAIL; \
|
||||
/* Getting and setting directory can be slow on some systems, only do */ \
|
||||
/* this when the current or target window/tab have a local directory or */ \
|
||||
/* 'acd' is set. */ \
|
||||
if (curwin != wp \
|
||||
&& (curwin->w_localdir != NULL || wp->w_localdir != NULL \
|
||||
|| (curtab != tp && (curtab->tp_localdir != NULL || tp->tp_localdir != NULL)) \
|
||||
|| p_acd)) { \
|
||||
cwd_status_ = os_dirname((char_u *)cwd_, MAXPATHL); \
|
||||
} \
|
||||
/* If 'acd' is set, check we are using that directory. If yes, then */ \
|
||||
/* apply 'acd' afterwards, otherwise restore the current directory. */ \
|
||||
if (cwd_status_ == OK && p_acd) { \
|
||||
do_autochdir(); \
|
||||
apply_acd_ = os_dirname((char_u *)autocwd_, MAXPATHL) == OK && strcmp(cwd_, autocwd_) == 0; \
|
||||
} \
|
||||
switchwin_T switchwin_; \
|
||||
if (switch_win_noblock(&switchwin_, wp_, (tp), true) == OK) { \
|
||||
check_cursor(); \
|
||||
block; \
|
||||
} \
|
||||
restore_win_noblock(&switchwin_, true); \
|
||||
if (apply_acd_) { \
|
||||
do_autochdir(); \
|
||||
} else if (cwd_status_ == OK) { \
|
||||
os_chdir(cwd_); \
|
||||
} \
|
||||
/* Update the status line if the cursor moved. */ \
|
||||
if (win_valid(wp_) && !equalpos(curpos_, wp_->w_cursor)) { \
|
||||
wp_->w_redr_status = true; \
|
||||
} \
|
||||
/* In case the command moved the cursor or changed the Visual area, */ \
|
||||
/* check it is valid. */ \
|
||||
check_cursor(); \
|
||||
if (VIsual_active) { \
|
||||
check_pos(curbuf, &VIsual); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "eval/window.h.generated.h"
|
||||
#endif
|
||||
#endif // NVIM_EVAL_WINDOW_H
|
@ -32,9 +32,11 @@ hashpipe:write([[
|
||||
#include "nvim/cmdexpand.h"
|
||||
#include "nvim/cmdhist.h"
|
||||
#include "nvim/digraph.h"
|
||||
#include "nvim/eval/buffer.h"
|
||||
#include "nvim/eval/funcs.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/vars.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/ex_docmd.h"
|
||||
#include "nvim/ex_getln.h"
|
||||
#include "nvim/fold.h"
|
||||
|
@ -13,10 +13,10 @@
|
||||
#include "nvim/buffer_defs.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/drawscreen.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/funcs.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/ex_cmds_defs.h"
|
||||
#include "nvim/ex_docmd.h"
|
||||
#include "nvim/fold.h"
|
||||
|
@ -22,9 +22,9 @@
|
||||
#include "nvim/diff.h"
|
||||
#include "nvim/drawscreen.h"
|
||||
#include "nvim/edit.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/fold.h"
|
||||
#include "nvim/getchar.h"
|
||||
#include "nvim/globals.h"
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/ex_cmds.h"
|
||||
#include "nvim/ex_cmds2.h"
|
||||
#include "nvim/ex_cmds_defs.h"
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/eval/vars.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/ex_cmds.h"
|
||||
#include "nvim/ex_cmds2.h"
|
||||
#include "nvim/ex_docmd.h"
|
||||
@ -7278,114 +7279,6 @@ static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr)
|
||||
return wp;
|
||||
}
|
||||
|
||||
/// Set "win" to be the curwin and "tp" to be the current tab page.
|
||||
/// restore_win() MUST be called to undo, also when FAIL is returned.
|
||||
/// No autocommands will be executed until restore_win() is called.
|
||||
///
|
||||
/// @param no_display if true the display won't be affected, no redraw is
|
||||
/// triggered, another tabpage access is limited.
|
||||
///
|
||||
/// @return FAIL if switching to "win" failed.
|
||||
int switch_win(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display)
|
||||
{
|
||||
block_autocmds();
|
||||
return switch_win_noblock(switchwin, win, tp, no_display);
|
||||
}
|
||||
|
||||
// As switch_win() but without blocking autocommands.
|
||||
int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display)
|
||||
{
|
||||
CLEAR_POINTER(switchwin);
|
||||
switchwin->sw_curwin = curwin;
|
||||
if (win == curwin) {
|
||||
switchwin->sw_same_win = true;
|
||||
} else {
|
||||
// Disable Visual selection, because redrawing may fail.
|
||||
switchwin->sw_visual_active = VIsual_active;
|
||||
VIsual_active = false;
|
||||
}
|
||||
|
||||
if (tp != NULL) {
|
||||
switchwin->sw_curtab = curtab;
|
||||
if (no_display) {
|
||||
curtab->tp_firstwin = firstwin;
|
||||
curtab->tp_lastwin = lastwin;
|
||||
curtab = tp;
|
||||
firstwin = curtab->tp_firstwin;
|
||||
lastwin = curtab->tp_lastwin;
|
||||
} else {
|
||||
goto_tabpage_tp(tp, false, false);
|
||||
}
|
||||
}
|
||||
if (!win_valid(win)) {
|
||||
return FAIL;
|
||||
}
|
||||
curwin = win;
|
||||
curbuf = curwin->w_buffer;
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Restore current tabpage and window saved by switch_win(), if still valid.
|
||||
// When "no_display" is true the display won't be affected, no redraw is
|
||||
// triggered.
|
||||
void restore_win(switchwin_T *switchwin, bool no_display)
|
||||
{
|
||||
restore_win_noblock(switchwin, no_display);
|
||||
unblock_autocmds();
|
||||
}
|
||||
|
||||
// As restore_win() but without unblocking autocommands.
|
||||
void restore_win_noblock(switchwin_T *switchwin, bool no_display)
|
||||
{
|
||||
if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab)) {
|
||||
if (no_display) {
|
||||
curtab->tp_firstwin = firstwin;
|
||||
curtab->tp_lastwin = lastwin;
|
||||
curtab = switchwin->sw_curtab;
|
||||
firstwin = curtab->tp_firstwin;
|
||||
lastwin = curtab->tp_lastwin;
|
||||
} else {
|
||||
goto_tabpage_tp(switchwin->sw_curtab, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!switchwin->sw_same_win) {
|
||||
VIsual_active = switchwin->sw_visual_active;
|
||||
}
|
||||
|
||||
if (win_valid(switchwin->sw_curwin)) {
|
||||
curwin = switchwin->sw_curwin;
|
||||
curbuf = curwin->w_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/// Make "buf" the current buffer.
|
||||
///
|
||||
/// restore_buffer() MUST be called to undo.
|
||||
/// No autocommands will be executed. Use aucmd_prepbuf() if there are any.
|
||||
void switch_buffer(bufref_T *save_curbuf, buf_T *buf)
|
||||
{
|
||||
block_autocmds();
|
||||
set_bufref(save_curbuf, curbuf);
|
||||
curbuf->b_nwindows--;
|
||||
curbuf = buf;
|
||||
curwin->w_buffer = buf;
|
||||
curbuf->b_nwindows++;
|
||||
}
|
||||
|
||||
/// Restore the current buffer after using switch_buffer().
|
||||
void restore_buffer(bufref_T *save_curbuf)
|
||||
{
|
||||
unblock_autocmds();
|
||||
// Check for valid buffer, just in case.
|
||||
if (bufref_valid(save_curbuf)) {
|
||||
curbuf->b_nwindows--;
|
||||
curwin->w_buffer = save_curbuf->br_buf;
|
||||
curbuf = save_curbuf->br_buf;
|
||||
curbuf->b_nwindows++;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that "topfrp" and its children are at the right height.
|
||||
///
|
||||
/// @param topfrp top frame pointer
|
||||
@ -7508,43 +7401,6 @@ skip:
|
||||
return NULL; // no error
|
||||
}
|
||||
|
||||
int win_getid(typval_T *argvars)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_UNKNOWN) {
|
||||
return curwin->handle;
|
||||
}
|
||||
int winnr = (int)tv_get_number(&argvars[0]);
|
||||
win_T *wp;
|
||||
if (winnr > 0) {
|
||||
if (argvars[1].v_type == VAR_UNKNOWN) {
|
||||
wp = firstwin;
|
||||
} else {
|
||||
tabpage_T *tp = NULL;
|
||||
int tabnr = (int)tv_get_number(&argvars[1]);
|
||||
FOR_ALL_TABS(tp2) {
|
||||
if (--tabnr == 0) {
|
||||
tp = tp2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (tp == curtab) {
|
||||
wp = firstwin;
|
||||
} else {
|
||||
wp = tp->tp_firstwin;
|
||||
}
|
||||
}
|
||||
for (; wp != NULL; wp = wp->w_next) {
|
||||
if (--winnr == 0) {
|
||||
return wp->handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void win_get_tabwin(handle_T id, int *tabnr, int *winnr)
|
||||
{
|
||||
*tabnr = 0;
|
||||
@ -7565,98 +7421,6 @@ void win_get_tabwin(handle_T id, int *tabnr, int *winnr)
|
||||
}
|
||||
}
|
||||
|
||||
void win_id2tabwin(typval_T *const argvars, typval_T *const rettv)
|
||||
{
|
||||
handle_T id = (handle_T)tv_get_number(&argvars[0]);
|
||||
|
||||
int winnr = 1;
|
||||
int tabnr = 1;
|
||||
win_get_tabwin(id, &tabnr, &winnr);
|
||||
|
||||
list_T *const list = tv_list_alloc_ret(rettv, 2);
|
||||
tv_list_append_number(list, tabnr);
|
||||
tv_list_append_number(list, winnr);
|
||||
}
|
||||
|
||||
win_T *win_id2wp(int id)
|
||||
{
|
||||
return win_id2wp_tp(id, NULL);
|
||||
}
|
||||
|
||||
// Return the window and tab pointer of window "id".
|
||||
win_T *win_id2wp_tp(int id, tabpage_T **tpp)
|
||||
{
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (wp->handle == id) {
|
||||
if (tpp != NULL) {
|
||||
*tpp = tp;
|
||||
}
|
||||
return wp;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int win_id2win(typval_T *argvars)
|
||||
{
|
||||
int nr = 1;
|
||||
int id = (int)tv_get_number(&argvars[0]);
|
||||
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->handle == id) {
|
||||
return nr;
|
||||
}
|
||||
nr++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void win_findbuf(typval_T *argvars, list_T *list)
|
||||
{
|
||||
int bufnr = (int)tv_get_number(&argvars[0]);
|
||||
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
if (wp->w_buffer->b_fnum == bufnr) {
|
||||
tv_list_append_number(list, wp->handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the layout of the given tab page for winlayout().
|
||||
void get_framelayout(const frame_T *fr, list_T *l, bool outer)
|
||||
{
|
||||
if (fr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
list_T *fr_list;
|
||||
if (outer) {
|
||||
// outermost call from f_winlayout()
|
||||
fr_list = l;
|
||||
} else {
|
||||
fr_list = tv_list_alloc(2);
|
||||
tv_list_append_list(l, fr_list);
|
||||
}
|
||||
|
||||
if (fr->fr_layout == FR_LEAF) {
|
||||
if (fr->fr_win != NULL) {
|
||||
tv_list_append_string(fr_list, "leaf", -1);
|
||||
tv_list_append_number(fr_list, fr->fr_win->handle);
|
||||
}
|
||||
} else {
|
||||
tv_list_append_string(fr_list, fr->fr_layout == FR_ROW ? "row" : "col", -1);
|
||||
|
||||
list_T *const win_list = tv_list_alloc(kListLenUnknown);
|
||||
tv_list_append_list(fr_list, win_list);
|
||||
const frame_T *child = fr->fr_child;
|
||||
while (child != NULL) {
|
||||
get_framelayout(child, win_list, false);
|
||||
child = child->fr_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void win_ui_flush(bool validate)
|
||||
{
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
|
@ -35,62 +35,6 @@
|
||||
#define MIN_COLUMNS 12 // minimal columns for screen
|
||||
#define MIN_LINES 2 // minimal lines for screen
|
||||
|
||||
/// Structure used by switch_win() to pass values to restore_win()
|
||||
typedef struct {
|
||||
win_T *sw_curwin;
|
||||
tabpage_T *sw_curtab;
|
||||
bool sw_same_win; ///< VIsual_active was not reset
|
||||
bool sw_visual_active;
|
||||
} switchwin_T;
|
||||
|
||||
/// Execute a block of code in the context of window `wp` in tabpage `tp`.
|
||||
/// Ensures the status line is redrawn and cursor position is valid if it is moved.
|
||||
#define WIN_EXECUTE(wp, tp, block) \
|
||||
do { \
|
||||
win_T *const wp_ = (wp); \
|
||||
const pos_T curpos_ = wp_->w_cursor; \
|
||||
char cwd_[MAXPATHL]; \
|
||||
char autocwd_[MAXPATHL]; \
|
||||
bool apply_acd_ = false; \
|
||||
int cwd_status_ = FAIL; \
|
||||
/* Getting and setting directory can be slow on some systems, only do */ \
|
||||
/* this when the current or target window/tab have a local directory or */ \
|
||||
/* 'acd' is set. */ \
|
||||
if (curwin != wp \
|
||||
&& (curwin->w_localdir != NULL || wp->w_localdir != NULL \
|
||||
|| (curtab != tp && (curtab->tp_localdir != NULL || tp->tp_localdir != NULL)) \
|
||||
|| p_acd)) { \
|
||||
cwd_status_ = os_dirname((char_u *)cwd_, MAXPATHL); \
|
||||
} \
|
||||
/* If 'acd' is set, check we are using that directory. If yes, then */ \
|
||||
/* apply 'acd' afterwards, otherwise restore the current directory. */ \
|
||||
if (cwd_status_ == OK && p_acd) { \
|
||||
do_autochdir(); \
|
||||
apply_acd_ = os_dirname((char_u *)autocwd_, MAXPATHL) == OK && strcmp(cwd_, autocwd_) == 0; \
|
||||
} \
|
||||
switchwin_T switchwin_; \
|
||||
if (switch_win_noblock(&switchwin_, wp_, (tp), true) == OK) { \
|
||||
check_cursor(); \
|
||||
block; \
|
||||
} \
|
||||
restore_win_noblock(&switchwin_, true); \
|
||||
if (apply_acd_) { \
|
||||
do_autochdir(); \
|
||||
} else if (cwd_status_ == OK) { \
|
||||
os_chdir(cwd_); \
|
||||
} \
|
||||
/* Update the status line if the cursor moved. */ \
|
||||
if (win_valid(wp_) && !equalpos(curpos_, wp_->w_cursor)) { \
|
||||
wp_->w_redr_status = true; \
|
||||
} \
|
||||
/* In case the command moved the cursor or changed the Visual area, */ \
|
||||
/* check it is valid. */ \
|
||||
check_cursor(); \
|
||||
if (VIsual_active) { \
|
||||
check_pos(curbuf, &VIsual); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "window.h.generated.h"
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user