// 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
// help.c: functions for Vim help
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/fileio.h"
#include "nvim/garray.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
#include "nvim/help.h"
#include "nvim/macros.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option.h"
#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/path.h"
#include "nvim/pos.h"
#include "nvim/runtime.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
#include "nvim/types.h"
#include "nvim/vim.h"
#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "help.c.generated.h"
#endif
/// ":help": open a read-only window on a help file
void ex_help(exarg_T *eap)
{
char *arg;
char *tag;
FILE *helpfd; // file descriptor of help file
int n;
int i;
win_T *wp;
int num_matches;
char **matches;
char *p;
int empty_fnum = 0;
int alt_fnum = 0;
buf_T *buf;
int len;
char *lang;
const bool old_KeyTyped = KeyTyped;
if (eap != NULL) {
// A ":help" command ends at the first LF, or at a '|' that is
// followed by some text. Set nextcmd to the following command.
for (arg = eap->arg; *arg; arg++) {
if (*arg == '\n' || *arg == '\r'
|| (*arg == '|' && arg[1] != NUL && arg[1] != '|')) {
*arg++ = NUL;
eap->nextcmd = arg;
break;
}
}
arg = eap->arg;
if (eap->forceit && *arg == NUL && !curbuf->b_help) {
emsg(_("E478: Don't panic!"));
return;
}
if (eap->skip) { // not executing commands
return;
}
} else {
arg = "";
}
// remove trailing blanks
p = arg + strlen(arg) - 1;
while (p > arg && ascii_iswhite(*p) && p[-1] != '\\') {
*p-- = NUL;
}
// Check for a specified language
lang = check_help_lang(arg);
// When no argument given go to the index.
if (*arg == NUL) {
arg = "help.txt";
}
// Check if there is a match for the argument.
n = find_help_tags(arg, &num_matches, &matches, eap != NULL && eap->forceit);
i = 0;
if (n != FAIL && lang != NULL) {
// Find first item with the requested language.
for (i = 0; i < num_matches; i++) {
len = (int)strlen(matches[i]);
if (len > 3 && matches[i][len - 3] == '@'
&& STRICMP(matches[i] + len - 2, lang) == 0) {
break;
}
}
}
if (i >= num_matches || n == FAIL) {
if (lang != NULL) {
semsg(_("E661: Sorry, no '%s' help for %s"), lang, arg);
} else {
semsg(_("E149: Sorry, no help for %s"), arg);
}
if (n != FAIL) {
FreeWild(num_matches, matches);
}
return;
}
// The first match (in the requested language) is the best match.
tag = xstrdup(matches[i]);
FreeWild(num_matches, matches);
// Re-use an existing help window or open a new one.
// Always open a new one for ":tab help".
if (!bt_help(curwin->w_buffer) || cmdmod.cmod_tab != 0) {
if (cmdmod.cmod_tab != 0) {
wp = NULL;
} else {
wp = NULL;
FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) {
if (bt_help(wp2->w_buffer)) {
wp = wp2;
break;
}
}
}
if (wp != NULL && wp->w_buffer->b_nwindows > 0) {
win_enter(wp, true);
} else {
// There is no help window yet.
// Try to open the file specified by the "helpfile" option.
if ((helpfd = os_fopen(p_hf, READBIN)) == NULL) {
smsg(_("Sorry, help file \"%s\" not found"), p_hf);
goto erret;
}
fclose(helpfd);
// Split off help window; put it at far top if no position
// specified, the current window is vertically split and
// narrow.
n = WSP_HELP;
if (cmdmod.cmod_split == 0 && curwin->w_width != Columns
&& curwin->w_width < 80) {
n |= p_sb ? WSP_BOT : WSP_TOP;
}
if (win_split(0, n) == FAIL) {
goto erret;
}
if (curwin->w_height < p_hh) {
win_setheight((int)p_hh);
}
// Open help file (do_ecmd() will set b_help flag, readfile() will
// set b_p_ro flag).
// Set the alternate file to the previously edited file.
alt_fnum = curbuf->b_fnum;
(vo
|