parse: some simple syncs and include syncs
Addition of dependency.c/h and promise.c/h. Also moved tagEntryFunction definitions to geany.c/h.
This commit is contained in:
parent
2f83d0d164
commit
051b780745
@ -58,6 +58,8 @@ libctags_la_SOURCES = \
|
||||
main/ctags.h \
|
||||
main/debug.h \
|
||||
main/debug.c \
|
||||
main/dependency.h \
|
||||
main/dependency.c \
|
||||
main/e_msoft.h \
|
||||
main/entry.c \
|
||||
main/entry.h \
|
||||
@ -101,6 +103,8 @@ libctags_la_SOURCES = \
|
||||
main/parsers.h \
|
||||
main/pcoproc.c \
|
||||
main/pcoproc.h \
|
||||
main/promise.c \
|
||||
main/promise.h \
|
||||
main/ptag.c \
|
||||
main/ptag.h \
|
||||
main/ptrarray.c \
|
||||
|
102
ctags/main/dependency.c
Normal file
102
ctags/main/dependency.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, Red Hat, Inc.
|
||||
* Copyright (c) 2016, Masatake YAMATO
|
||||
*
|
||||
* Author: Masatake YAMATO <yamato@redhat.com>
|
||||
*
|
||||
* This source code is released for free distribution under the terms of the
|
||||
* GNU General Public License version 2 or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "general.h" /* must always come first */
|
||||
|
||||
#include "dependency.h"
|
||||
#include "parse.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static void linkKinds (kindOption *masterKind, kindOption *slaveKind)
|
||||
{
|
||||
kindOption *tail;
|
||||
|
||||
slaveKind->master = masterKind;
|
||||
|
||||
tail = slaveKind;
|
||||
while (tail->slave)
|
||||
{
|
||||
tail->enabled = masterKind->enabled;
|
||||
tail = tail->slave;
|
||||
}
|
||||
|
||||
tail->slave = masterKind->slave;
|
||||
masterKind->slave = slaveKind;
|
||||
}
|
||||
|
||||
static void linkKindDependency (parserDefinition *const masterParser,
|
||||
parserDefinition *const slaveParser)
|
||||
{
|
||||
unsigned int k_slave, k_master;
|
||||
kindOption *kind_slave, *kind_master;
|
||||
|
||||
for (k_slave = 0; k_slave < slaveParser->kindCount; k_slave++)
|
||||
{
|
||||
if (slaveParser->kinds [k_slave].syncWith == LANG_AUTO)
|
||||
{
|
||||
kind_slave = slaveParser->kinds + k_slave;
|
||||
for (k_master = 0; k_master < masterParser->kindCount; k_master++)
|
||||
{
|
||||
kind_master = masterParser->kinds + k_master;
|
||||
if ((kind_slave->letter == kind_master->letter)
|
||||
&& (strcmp (kind_slave->name, kind_master->name) == 0))
|
||||
{
|
||||
linkKinds (kind_master, kind_slave);
|
||||
kind_slave->syncWith = masterParser->id;
|
||||
kind_master->syncWith = masterParser->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void linkDependencyAtInitializeParsing (depType dtype,
|
||||
parserDefinition *const masterParser,
|
||||
parserDefinition *const slaveParser)
|
||||
{
|
||||
if (dtype == DEPTYPE_KIND_OWNER)
|
||||
linkKindDependency (masterParser, slaveParser);
|
||||
else if (dtype == DEPTYPE_SUBPARSER)
|
||||
{
|
||||
subparser *s = xMalloc (1, subparser);
|
||||
|
||||
s->id = slaveParser->id;
|
||||
s->next = masterParser->subparsers;
|
||||
masterParser->subparsers = s;
|
||||
}
|
||||
}
|
||||
|
||||
extern void initializeSubparsers (const parserDefinition *parser)
|
||||
{
|
||||
subparser *sp;
|
||||
|
||||
for (sp = parser->subparsers; sp; sp = sp->next)
|
||||
initializeParser (sp->id);
|
||||
}
|
||||
|
||||
extern void finalizeSubparsers (parserDefinition *parser)
|
||||
{
|
||||
subparser *sp;
|
||||
subparser *tmp;
|
||||
|
||||
for (sp = parser->subparsers; sp;)
|
||||
{
|
||||
tmp = sp;
|
||||
sp = sp->next;
|
||||
tmp->next = NULL;
|
||||
eFree (tmp);
|
||||
}
|
||||
parser->subparsers = NULL;
|
||||
}
|
45
ctags/main/dependency.h
Normal file
45
ctags/main/dependency.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, Red Hat, Inc.
|
||||
* Copyright (c) 2016, Masatake YAMATO
|
||||
*
|
||||
* Author: Masatake YAMATO <yamato@redhat.com>
|
||||
*
|
||||
* This source code is released for free distribution under the terms of the
|
||||
* GNU General Public License version 2 or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
#ifndef CTAGS_MAIN_DEPENDENCY_H
|
||||
#define CTAGS_MAIN_DEPENDENCY_H
|
||||
|
||||
#include "general.h"
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
typedef enum eDepType {
|
||||
DEPTYPE_KIND_OWNER,
|
||||
DEPTYPE_SUBPARSER,
|
||||
COUNT_DEPTYPES,
|
||||
} depType;
|
||||
|
||||
typedef struct sParserDependency {
|
||||
depType type;
|
||||
const char *upperParser;
|
||||
void *data;
|
||||
} parserDependency;
|
||||
|
||||
extern void linkDependencyAtInitializeParsing (depType dtype,
|
||||
parserDefinition *const masterParser,
|
||||
parserDefinition *const slaveParser);
|
||||
|
||||
typedef struct sSubparser subparser;
|
||||
struct sSubparser {
|
||||
langType id;
|
||||
subparser *next;
|
||||
};
|
||||
|
||||
extern void initializeSubparsers (const parserDefinition *parser);
|
||||
extern void finalizeSubparsers (parserDefinition *parser);
|
||||
|
||||
#endif /* CTAGS_MAIN_DEPENDENCY_H */
|
@ -11,6 +11,7 @@
|
||||
* INCLUDE FILES
|
||||
*/
|
||||
#include "general.h" /* must always come first */
|
||||
#include "geany.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h> /* to define isspace () */
|
||||
@ -1092,8 +1093,7 @@ static void writeTagEntry (const tagEntryInfo *const tag)
|
||||
buildFqTagCache (tag);
|
||||
*/
|
||||
/* length = writer->writeEntry (TagFile.mio, tag, writerData); */
|
||||
if (TagEntryFunction != NULL)
|
||||
length = TagEntryFunction(tag, TagEntryUserData);
|
||||
length = callTagEntryFunction (tag);
|
||||
|
||||
++TagFile.numTags.added;
|
||||
rememberMaxLengths (strlen (tag->name), (size_t) length);
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
|
||||
static tagEntryFunction TagEntryFunction = NULL;
|
||||
static void *TagEntryUserData = NULL;
|
||||
|
||||
/* tags_ignore is a NULL-terminated array of strings, read from ~/.config/geany/ignore.tags.
|
||||
* This file contains a space or newline separated list of symbols which should be ignored
|
||||
* by the C/C++ parser, see -I command line option of ctags for details. */
|
||||
@ -78,3 +81,17 @@ extern bool isIgnoreToken (const char *const name,
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern void setTagEntryFunction(tagEntryFunction entry_function, void *user_data)
|
||||
{
|
||||
TagEntryFunction = entry_function;
|
||||
TagEntryUserData = user_data;
|
||||
}
|
||||
|
||||
extern int callTagEntryFunction(const tagEntryInfo *const tag)
|
||||
{
|
||||
int length = 0;
|
||||
if (TagEntryFunction != NULL)
|
||||
length = TagEntryFunction(tag, TagEntryUserData);
|
||||
return length;
|
||||
}
|
||||
|
@ -9,6 +9,14 @@
|
||||
#ifndef CTAGS_GEANY_H
|
||||
#define CTAGS_GEANY_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef int (*tagEntryFunction) (const tagEntryInfo *const tag, void *user_data);
|
||||
|
||||
|
||||
extern bool isIgnoreToken (const char *const name, bool *const pIgnoreParens, const char **const replacement);
|
||||
|
||||
extern void setTagEntryFunction(tagEntryFunction entry_function, void *user_data);
|
||||
extern int callTagEntryFunction(const tagEntryInfo *const tag);
|
||||
|
||||
#endif /* CTAGS_GEANY_H */
|
||||
|
@ -16,16 +16,21 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "mio.h"
|
||||
#include "entry.h"
|
||||
#include "flags.h"
|
||||
#include "keyword.h"
|
||||
#include "main.h"
|
||||
#define OPTION_WRITE
|
||||
#include "options.h"
|
||||
#include "parsers.h"
|
||||
#include "promise.h"
|
||||
#include "ptag.h"
|
||||
#include "read.h"
|
||||
#include "vstring.h"
|
||||
#include "routines.h"
|
||||
#include "vstring.h"
|
||||
#ifdef HAVE_ICONV
|
||||
# include "mbcs.h"
|
||||
#endif
|
||||
#include "xtag.h"
|
||||
|
||||
/*
|
||||
@ -41,20 +46,10 @@ static kindOption defaultFileKind = {
|
||||
.description = KIND_FILE_DEFAULT_LONG,
|
||||
};
|
||||
|
||||
tagEntryFunction TagEntryFunction = NULL;
|
||||
void *TagEntryUserData = NULL;
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
extern void setTagEntryFunction(tagEntryFunction entry_function, void *user_data)
|
||||
{
|
||||
TagEntryFunction = entry_function;
|
||||
TagEntryUserData = user_data;
|
||||
}
|
||||
|
||||
|
||||
extern void makeSimpleTag (const vString* const name,
|
||||
kindOption* const kinds, const int kind)
|
||||
{
|
||||
@ -287,6 +282,12 @@ extern void addLanguageExtensionMap (const langType language,
|
||||
stringListAdd (LanguageTable [language]->currentExtensions, str);
|
||||
}
|
||||
|
||||
extern void enableLanguage (const langType language, const bool state)
|
||||
{
|
||||
Assert (0 <= language && language < (int) LanguageCount);
|
||||
LanguageTable [language]->enabled = state;
|
||||
}
|
||||
|
||||
extern void enableLanguages (const bool state)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -294,12 +295,6 @@ extern void enableLanguages (const bool state)
|
||||
LanguageTable [i]->enabled = state;
|
||||
}
|
||||
|
||||
extern void enableLanguage (const langType language, const bool state)
|
||||
{
|
||||
Assert (0 <= language && language < (int) LanguageCount);
|
||||
LanguageTable [language]->enabled = state;
|
||||
}
|
||||
|
||||
static void initializeParserOne (langType lang)
|
||||
{
|
||||
parserDefinition *const parser = LanguageTable [lang];
|
||||
@ -371,22 +366,6 @@ extern void initializeParsing (void)
|
||||
initializeParsers ();
|
||||
}
|
||||
|
||||
extern void freeParserResources (void)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0 ; i < LanguageCount ; ++i)
|
||||
{
|
||||
freeList (&LanguageTable [i]->currentPatterns);
|
||||
freeList (&LanguageTable [i]->currentExtensions);
|
||||
eFree (LanguageTable [i]->name);
|
||||
LanguageTable [i]->name = NULL;
|
||||
eFree (LanguageTable [i]);
|
||||
}
|
||||
eFree (LanguageTable);
|
||||
LanguageTable = NULL;
|
||||
LanguageCount = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Option parsing
|
||||
*/
|
||||
@ -396,8 +375,14 @@ extern void processLanguageDefineOption (const char *const option,
|
||||
{
|
||||
}
|
||||
|
||||
extern bool processKindOption (const char *const option,
|
||||
const char *const parameter)
|
||||
extern bool processKindOption (
|
||||
const char *const option, const char *const parameter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
extern bool processAliasOption (
|
||||
const char *const option, const char *const parameter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -440,9 +425,3 @@ extern void installKeywordTable (const langType language)
|
||||
lang->keywordInstalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
extern bool processAliasOption (
|
||||
const char *const option, const char *const parameter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -13,10 +13,13 @@
|
||||
* INCLUDE FILES
|
||||
*/
|
||||
#include "general.h" /* must always come first */
|
||||
#include "types.h"
|
||||
|
||||
#include "dependency.h"
|
||||
#include "field.h"
|
||||
#include "kind.h"
|
||||
#include "parsers.h" /* contains list of parsers */
|
||||
#include "strlist.h"
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
* MACROS
|
||||
@ -32,7 +35,6 @@ typedef void (*createRegexTag) (const vString* const name);
|
||||
typedef void (*simpleParser) (void);
|
||||
typedef bool (*rescanParser) (const unsigned int passCount);
|
||||
typedef void (*parserInitialize) (langType language);
|
||||
typedef int (*tagEntryFunction) (const tagEntryInfo *const tag, void *user_data);
|
||||
|
||||
typedef enum {
|
||||
METHOD_NOT_CRAFTED = 1 << 0,
|
||||
@ -44,8 +46,8 @@ typedef enum {
|
||||
|
||||
typedef struct {
|
||||
const char *const regex;
|
||||
const char *const name;
|
||||
const char *const kinds;
|
||||
const char* const name;
|
||||
const char* const kinds;
|
||||
const char *const flags;
|
||||
bool *disabled;
|
||||
} tagRegexTable;
|
||||
@ -66,7 +68,7 @@ struct sParserDefinition {
|
||||
parserInitialize initialize; /* initialization routine, if needed */
|
||||
simpleParser parser; /* simple parser (common case) */
|
||||
rescanParser parser2; /* rescanning parser (unusual case) */
|
||||
unsigned int method; /* See PARSE__... definitions above */
|
||||
unsigned int method; /* See METHOD_ definitions above */
|
||||
|
||||
/* used internally */
|
||||
unsigned int id; /* id assigned to language */
|
||||
@ -79,6 +81,9 @@ struct sParserDefinition {
|
||||
unsigned int keywordCount;
|
||||
|
||||
unsigned int initialized:1; /* initialize() is called or not */
|
||||
subparser *subparsers; /* The parsers on this list must be initialized when
|
||||
this parser is initialized. */
|
||||
|
||||
unsigned int tagRegexInstalled:1; /* tagRegexTable is installed or not. */
|
||||
unsigned int keywordInstalled:1; /* keywordTable is installed or not. */
|
||||
};
|
||||
@ -86,7 +91,7 @@ struct sParserDefinition {
|
||||
typedef parserDefinition* (parserDefinitionFunc) (void);
|
||||
|
||||
typedef struct {
|
||||
int start; /* character index in line where match starts */
|
||||
size_t start; /* character index in line where match starts */
|
||||
size_t length; /* length of match */
|
||||
} regexMatch;
|
||||
|
||||
@ -98,6 +103,7 @@ typedef enum {
|
||||
LMAP_ALL = LMAP_PATTERN | LMAP_EXTENSION,
|
||||
} langmapType;
|
||||
|
||||
|
||||
/*
|
||||
* FUNCTION PROTOTYPES
|
||||
*/
|
||||
@ -131,7 +137,6 @@ extern void enableLanguages (const bool state);
|
||||
extern void enableLanguage (const langType language, const bool state);
|
||||
extern void initializeParsing (void);
|
||||
extern void initializeParser (langType language);
|
||||
extern void freeParserResources (void);
|
||||
extern void processLanguageDefineOption (const char *const option, const char *const parameter);
|
||||
extern bool processKindOption (const char *const option, const char *const parameter);
|
||||
|
||||
@ -147,15 +152,8 @@ extern void addTagRegex (const langType language, const char* const regex, const
|
||||
extern void addCallbackRegex (const langType language, const char* const regex, const char* flags, const regexCallback callback);
|
||||
extern void disableRegexKinds (const langType language CTAGS_ATTR_UNUSED);
|
||||
extern bool enableRegexKind (const langType language, const int kind, const bool mode);
|
||||
extern void printRegexKindOptions (const langType language);
|
||||
extern void printRegexKinds (const langType language, bool indent);
|
||||
extern void freeRegexResources (void);
|
||||
extern bool checkRegex (void);
|
||||
|
||||
|
||||
/* Extra stuff for Tag Manager */
|
||||
extern tagEntryFunction TagEntryFunction;
|
||||
extern void *TagEntryUserData;
|
||||
extern void setTagEntryFunction(tagEntryFunction entry_function, void *user_data);
|
||||
|
||||
#endif /* CTAGS_MAIN_PARSE_H */
|
||||
|
102
ctags/main/promise.c
Normal file
102
ctags/main/promise.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, Red Hat, Inc.
|
||||
* Copyright (c) 2016, Masatake YAMATO
|
||||
*
|
||||
* Author: Masatake YAMATO <yamato@redhat.com>
|
||||
*
|
||||
* This source code is released for free distribution under the terms of the
|
||||
* GNU General Public License version 2 or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "general.h"
|
||||
#include "promise.h"
|
||||
#include "debug.h"
|
||||
#include "xtag.h"
|
||||
|
||||
|
||||
struct promise {
|
||||
langType lang;
|
||||
unsigned long startLine;
|
||||
int startCharOffset;
|
||||
unsigned long endLine;
|
||||
int endCharOffset;
|
||||
unsigned long sourceLineOffset;
|
||||
};
|
||||
|
||||
static struct promise *promises;
|
||||
static int promise_count;
|
||||
static int promise_allocated;
|
||||
|
||||
int makePromise (const char *parser,
|
||||
unsigned long startLine, int startCharOffset,
|
||||
unsigned long endLine, int endCharOffset,
|
||||
unsigned long sourceLineOffset)
|
||||
{
|
||||
struct promise *p;
|
||||
int r;
|
||||
langType lang;
|
||||
|
||||
if (!isXtagEnabled (XTAG_TAGS_GENERATED_BY_SUB_PARSERS))
|
||||
return -1;
|
||||
|
||||
lang = getNamedLanguage (parser, 0);
|
||||
if (lang == LANG_IGNORE)
|
||||
return -1;
|
||||
|
||||
if ( promise_count == promise_allocated)
|
||||
{
|
||||
size_t c = promise_allocated? (promise_allocated * 2): 8;
|
||||
promises = xRealloc (promises, c, struct promise);
|
||||
promise_allocated = c;
|
||||
}
|
||||
|
||||
p = promises + promise_count;
|
||||
|
||||
p->lang = lang;
|
||||
p->startLine = startLine;
|
||||
p->startCharOffset = startCharOffset;
|
||||
p->endLine = endLine;
|
||||
p->endCharOffset = endCharOffset;
|
||||
p->sourceLineOffset = sourceLineOffset;
|
||||
|
||||
r = promise_count;
|
||||
promise_count++;
|
||||
return r;
|
||||
}
|
||||
|
||||
void breakPromisesAfter (int promise)
|
||||
{
|
||||
Assert (promise_count >= promise);
|
||||
|
||||
promise_count = promise;
|
||||
}
|
||||
|
||||
bool forcePromises (void)
|
||||
{
|
||||
int i;
|
||||
bool tagFileResized = false;
|
||||
|
||||
for (i = 0; i < promise_count; ++i)
|
||||
{
|
||||
struct promise *p = promises + i;
|
||||
/* tagFileResized = runParserInNarrowedInputStream (p->lang,
|
||||
p->startLine,
|
||||
p->startCharOffset,
|
||||
p->endLine,
|
||||
p->endCharOffset,
|
||||
p->sourceLineOffset)
|
||||
? true
|
||||
: tagFileResized;*/
|
||||
}
|
||||
|
||||
promise_count = 0;
|
||||
return tagFileResized;
|
||||
}
|
||||
|
||||
|
||||
int getLastPromise (void)
|
||||
{
|
||||
return promise_count - 1;
|
||||
}
|
27
ctags/main/promise.h
Normal file
27
ctags/main/promise.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, Red Hat, Inc.
|
||||
* Copyright (c) 2016, Masatake YAMATO
|
||||
*
|
||||
* Author: Masatake YAMATO <yamato@redhat.com>
|
||||
*
|
||||
* This source code is released for free distribution under the terms of the
|
||||
* GNU General Public License version 2 or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
#ifndef CTAGS_MAIN_PROMISE_H
|
||||
#define CTAGS_MAIN_PROMISE_H
|
||||
|
||||
#include "general.h"
|
||||
#include "mio.h"
|
||||
#include "parse.h"
|
||||
|
||||
int makePromise (const char *parser,
|
||||
unsigned long startLine, int startCharOffset,
|
||||
unsigned long endLine, int endCharOffset,
|
||||
unsigned long sourceLineOffset);
|
||||
bool forcePromises (void);
|
||||
void breakPromisesAfter (int promise);
|
||||
int getLastPromise (void);
|
||||
|
||||
#endif /* CTAGS_MAIN_PROMISE_H */
|
@ -21,6 +21,7 @@
|
||||
#include "read.h"
|
||||
#include "vstring.h"
|
||||
#include "routines.h"
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "vstring.h"
|
||||
#include "nestlevel.h"
|
||||
#include "routines.h"
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "read.h"
|
||||
#include "vstring.h"
|
||||
#include "routines.h"
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "read.h"
|
||||
#include "vstring.h"
|
||||
#include "routines.h"
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "vstring.h"
|
||||
#include "nestlevel.h"
|
||||
#include "routines.h"
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
* DATA DEFINITIONS
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "nestlevel.h"
|
||||
#include "vstring.h"
|
||||
#include "routines.h"
|
||||
#include "entry.h"
|
||||
|
||||
|
||||
/* as any character may happen in an input, use something highly unlikely */
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "entry.h"
|
||||
#include "parse.h"
|
||||
#include "read.h"
|
||||
|
||||
#include "geany.h"
|
||||
|
||||
typedef struct {
|
||||
TMCtagsNewTagCallback tag_callback;
|
||||
|
Loading…
x
Reference in New Issue
Block a user