Skip to content

Conversation

AlexandreDubray
Copy link
Contributor

reference #7388

_emsg is the same as emsg but has additionnal argument which is a pointer
to a function that is used to return the value
@marvim marvim added the WIP label Feb 5, 2018
*
* return TRUE if wait_return not called
*/
int emsg(const char_u *s_)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to have const char *s = (const char *)s_; line above as well as underscore here: underscore is only because of the existence of the line and line is there only because I did not feel like refactoring lots of emsg callers which use char_u.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, and here still is underscore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh god, I must be blind. Sorry for that, I will change it immediately so I will not forget anymore !

* return TRUE if wait_return not called
*/
int emsg(const char_u *s_)
static int _emsg(const char *s_, int (*msg_attr)(const char *s, const int attr))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is bad idea to mask symbols; also need typedef, AFAIR C declarations generator intentionally cannot swallow that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made the typedef in a commit but I did not understood the "mask symbol" part (I mean, technically what does that mean? I'm sorry, my knowledge of C is not that advanced).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It means that you should not define a symbol in some inner scope which is the same as a symbol in an outer scope. E.g. in

int i = 0;
{
  int i = 1;
  printf("%d\n", i);
}
printf("%d\n", i);

second i masks the first one. msg_attr is a function defined in compilation unit scope, and at the same time an argument to _emsg which means that it is redefined in _emsg functions scope.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed it was not smart, thanks for the explanation!

The added function behaves like the non-echo function but display message
in a echo-style way (i.e. tab and newline are preserved)
@@ -54,6 +54,8 @@ struct msgchunk_S {
char_u sb_text[1]; /* text to be displayed, actually longer */
};

typedef int (*fct_msg_attr)(const char *s, const int attr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New types should be CamelCase.

msg_echo_attr_keep(
const char *s,
const int attr,
int keep
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You must not put arguments completely on separate lines unless you absolutely have to. Neither separate type from function name or closing parenthesis from the last argument.

const int attr,
int keep
)
FUNC_ATTR_NONNULL_ARG(1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FUNC_ATTR_NONNULL_ALL may be used when all pointer arguments are non-NULL. Non-pointer ones do not matter.

@@ -577,9 +666,9 @@ static int _emsg(const char *s_, int (*msg_attr)(const char *s, const int attr))
*/
int emsg(const char_u *s_)
{
return _emsg((const char *)s_, &msg_attr);
fct_msg_attr f = &msg_attr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not create temporary variable here, code should work as it worked.

buf = (char *)msg_strtrunc((char_u *)s, false);
if (buf != NULL) {
s = buf;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too much copy-paste.


char * spec_char = "\t\n\r";

char * next_spec = (char *)s;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should not be space after asterisk.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And next_spec must be const char *. Do not cast to char * until needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I.e. until going to legacy (unrefactored) msg_outtrans[_len]_attr.

s = buf;
}

char * spec_char = "\t\n\r";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not make compiler work harder, strpbrk argument better be a literal, either just literal or macros. But since you are using this list in a single place just put literal there.

char * next_spec = (char *)s;

while (next_spec != NULL) {
next_spec = (char *)vim_strpbrk(s, spec_char);
Copy link
Contributor

@ZyX-I ZyX-I Feb 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You just added a bunch of useless casts here (some hidden by vim_strpbrk macros), don’t use vim_strpbrk, use strpbrk directly.

@@ -606,6 +713,19 @@ static bool emsgfv(const char *fmt, va_list ap)
return emsg((const char_u *)errbuf);
}

static bool emsgfv_echo(const char *fmt, va_list ap)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is short and not used anywhere, but in emsgf_echo, so should not exist.

@@ -572,7 +653,21 @@ int emsg(const char_u *s_)

// Display the error message itself.
msg_nowait = false; // Wait for this msg.
return msg_attr(s, attr);
return ret_fct(s, attr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ret_fct is a strange name. I would go with something like display_msg.

@AlexandreDubray
Copy link
Contributor Author

@ZyX-I I think I've modified everything you pointed out. Still I'm not sure about the "too much copy-paste" comment. Let me know if I need to modify anything :-)

}

int
msg_echo_attr_keep(const char *s, const int attr, int keep)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are still separating type from function name. Correct examples of formatting are new files like src/nvim/eval/typval.c, not legacy code here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, function returns boolean.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it is logical to either have const int keep or int attr. I normally prefer putting const everywhere I can.

@@ -137,6 +139,81 @@ int msg_attr(const char *s, const int attr) FUNC_ATTR_NONNULL_ARG(1)
return msg_attr_keep((char_u *)s, attr, false);
}

int msg_echo_attr(const char *s, const int attr) FUNC_ATTR_NONNULL_ARG(1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not put FUNC_ATTR on the same line as a function name, this variant both visually hides attributes and produces unneccessary line change if something needs to be added (e.g. new argument or another attribute).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, is this a function intended to be used in ex_echo? It is not good to have two implementations doing essentially the same task; also using function there makes testing a lot easier and allows CI to catch errors before test suite is good enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not intend to use it in ex_echo, but I guess I could modify ex_echo to use it (if it is the purpose of the question)

msg_echo_attr_keep(const char *s, const int attr, int keep)
FUNC_ATTR_NONNULL_ALL
{
static int entered = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function contains too many copy-paste from its origin, common code should not be copied if possible.

{
static int entered = 0;
int retval;
char * buf = NULL;
Copy link
Contributor

@ZyX-I ZyX-I Feb 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here asterisk is formatted as multiplication, but it is not.

}

msg_start();
buf = (char *)msg_strtrunc((char_u *)s, false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And if you do refactor old code, move variable definitions closer to the place where they are actually used. It should be char *const buf here.

s = buf;
}

const char *spec_char = "\t\n\r";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variable still has no reason to exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, I misunderstood your previous comment

FUNC_ATTR_NONNULL_ALL
{
static int entered = 0;
int retval;
Copy link
Contributor

@ZyX-I ZyX-I Feb 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one should not exist either, need const bool retval = msg_end() below.

retval = msg_end();

if (keep && retval && vim_strsize((char_u *)s) < (int)(Rows - cmdline_row -1)
* Columns + sc_col) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alignment is not correct.

{
return msg_echo_attr_keep(s, attr, false);
}

int
msg_echo_attr_keep(const char *s, const int attr, int keep)
bool msg_attr_skip(const char *s, const int attr, int *const call)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ZyX-I I move the common code into this function that return when the message doesn't need to be shown (I will add comments, I forgot them). Is the function ok for you?
Also, i didn't put the add_msg_hist here because (if I understood well the code) it is already done in msg_outtrans_len_attr and msg_puts_attr_len. I guess it doesn't need to be done multiple time?

@AlexandreDubray AlexandreDubray changed the title [WIP] Lua error message better formatting [RFC] Lua error message better formatting Feb 11, 2018
@marvim marvim added RFC and removed WIP labels Feb 11, 2018
* When terminal not initialized (yet) mch_errmsg(..) is used.
*
* return TRUE if wait_return not called
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please run make lint, it will notify you about lint problems.

@justinmk
Copy link
Member

typedef int (*FctMsgAttr)(const char *s, const int attr);

What is Fct? If it means "function", that's very unusual. Fn or Fun or Func are far more common. Use git grep to see existing examples:

git grep -E 'typedef.*\(.*\)' -- ':/*.c'

@AlexandreDubray
Copy link
Contributor Author

@justinmk Yep Fct was for function (old habits die hard ^^) corrected now! (plus the lint problem). I think it's ready if there is nothing else :-)

@AlexandreDubray AlexandreDubray changed the title [RFC] Lua error message better formatting [RDY] Lua error message better formatting Feb 13, 2018
@ZyX-I
Copy link
Contributor

ZyX-I commented Feb 13, 2018

I do not see new code used for echo. Also missing tests including outputting following messages:

  1. Regular ones with multiline stack trace.
  2. Single-line regular (i.e. what a sane developer would want to throw with error()) ones.
  3. Consisting of just three newlines, three tabs and three \rs and nothing else. (These are three cases, not one).
  4. Long (longer then screen width) single-line ones with tabs inside.
  5. Multiline with long (…) lines.
  6. Just empty string.

That list repeated for

  1. Throwing lua errors and displaying them on screen.
  2. Throwing lua errors and catching them with redir, execute() or nvim_command_output (since it is easier to write test generator then repeat tests it would make sense to use all variants).
  3. Throwing lua errors and catching them with :try|catch.
  4. Echoing messages with :echo and displaying them on screen.
  5. Echoing messages with :echon and displaying them on screen.
  6. Echoing messages with :echo and catching them with redir/… (…).
  7. Echoing messages with :echon and catching them with … (…).

As I said I would expect you to write a test generator rather then lots of boilerplate tests.

@AlexandreDubray
Copy link
Contributor Author

Oh yeah, I forget this story about the echo, will do that. And also, what do you mean exactly by test generator ?

@AlexandreDubray AlexandreDubray changed the title [RDY] Lua error message better formatting [RFC] Lua error message better formatting Feb 13, 2018
@ZyX-I
Copy link
Contributor

ZyX-I commented Feb 13, 2018

Normally you write tests like describe('text', function() it('text', function() --[[ actual test ]] end) end), placing that directly in the file. By “test generator” I mean some lua function which calls describe() and/or it() with computed text and actual test being a closure acting based on test generator arguments. It is used throught the test code for creating similar tests: e.g. in https://github.com/ZyX-I/neovim/blob/5c84d48b1f0ba2400ffb06f20ceb2da3e0590261/test/functional/eval/null_spec.lua or https://github.com/ZyX-I/neovim/blob/5c84d48b1f0ba2400ffb06f20ceb2da3e0590261/test/functional/ex_cmds/append_spec.lua.

@AlexandreDubray
Copy link
Contributor Author

Ok, thanks for the references, I will look at that.

@justinmk
Copy link
Member

Merged by #9520. Would be good if someone implemented the tests mentioned in #7969 (comment) .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants