Skip to content

Conversation

nimitbhardwaj
Copy link
Contributor

Add the nvim_get_commands API function,
Returns the dictionary of commands.

@nimitbhardwaj
Copy link
Contributor Author

Presently just a prototype, means it works list the command successfully, but some necessary things like documentation, tests are omitted, will be added soon, It first needs to be reviewed

return ucmds.ga_len;
}

Dictionary get_dict_command(int i) {
Copy link
Member

Choose a reason for hiding this comment

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

I think you can have the function return an Array directly, then separate n_get_commands is not needed.

Dictionary get_dict_command(int i) {
Dictionary dic = ARRAY_DICT_INIT;
ucmd_T *cmd = USER_CMD(i);
PUT(dic, "uc_name", STRING_OBJ(cstr_to_string((const char *)cmd->uc_name)));
Copy link
Member

Choose a reason for hiding this comment

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

these are the internal names, we don't want them in external API. Better to use terms mentioned in documentation :help command.

@nimitbhardwaj nimitbhardwaj changed the title Add the nvim_get_commands function [RFC] Add the nvim_get_commands function Feb 25, 2018
@nimitbhardwaj
Copy link
Contributor Author

Made the necessary adjustments by seeing the uc_list, but if there is a room for adjustments I would be happy to do so, and after that my work is adding documentation and testing

@nimitbhardwaj
Copy link
Contributor Author

And during testing, I want to know how to do its testing in lua, means we apply command and get output?

@marvim marvim added the RFC label Feb 25, 2018
@nimitbhardwaj
Copy link
Contributor Author

Is it right or something to be done.

@bfredl
Copy link
Member

bfredl commented Feb 25, 2018

check test/functional/api/vim_spec.lua (and rest of api/ directory) for tests of API function. Tests for keymap api/keymap_spec.lua might be inspiration.

Also just like nvim_get_keymap has nvim_buf_get_keymap, we will need nvim_buf_get_commands variant for buffer local commands. (buf->b_ucmds)

@nimitbhardwaj
Copy link
Contributor Author

OK, this will be done

@nimitbhardwaj
Copy link
Contributor Author

Now I make the tests

PUT(dic, "ScriptID", INTEGER_OBJ(cmd->uc_scriptID));

// Compl Arg
PUT(dic, "Compl Arg",
Copy link
Member

Choose a reason for hiding this comment

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

key names never have whitespace and are never capitalized.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Was thinking of Compl Arg same, didn't get the feel of a coder here, I change it

/// @param[in] buf the specified buffer, if NULL then global commands required
///
/// @return The array of the commands and the information of each command
ArrayOf(Dictionary) get_commands(buf_T *buf)
Copy link
Member

@justinmk justinmk Feb 26, 2018

Choose a reason for hiding this comment

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

Not sure if it's the best convention, but our current convention (for internal wrappers that convert internal structures to Array) is to name this commands_array.

Existing examples: mode_style_array, keymap_array. Until a better convention is found, we should always do the same thing, to avoid having numerous inconsistent patterns.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK got it

@nimitbhardwaj
Copy link
Contributor Author

Made the basic tests, by understanding the test of get_keymap, may be more things are to be added after it, but its basic of the tests I made


// Defination
PUT(dic, "Defination",
PUT(dic, "defination",
Copy link
Member

@justinmk justinmk Feb 27, 2018

Choose a reason for hiding this comment

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

typo, "definition" (also the comment above it, which probably should just be deleted)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okk, so, I think my english is sooo bad, I generally used defination, it was wrong, 😆

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And yes, I have to delete the comments?
I thought they are useful to see the code tidy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Today, I am laughing on myself, I didn't even know the spelling of Definition, how poor, haha haha 🤣

Copy link
Member

@justinmk justinmk Feb 27, 2018

Choose a reason for hiding this comment

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

@nimitbhardwaj No worries!

And yes, I have to delete the comments?

Trivial comments that restate the obvious aren't needed. But if they describe something non-obvious, or if they describe a group of lines, then they might be useful.

@nimitbhardwaj
Copy link
Contributor Author

I edited the typo, but should I remove all comments, that were added, I added them because I thought they provide the info and somewhat beautify the code.


// Complete
for (j = 0; command_complete[j].expand != 0; j++) {
if (cmd->uc_compl == command_complete[j].expand) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This operation can be made more fast, command_complete is just a static array, we manually inserted the items in it, if the items there are added in sorted order then by using binary search O(log(n)) complexity can be achieved instead of O(n), so possibliity can be just arange the items in array, replace linear search with bin search

Copy link
Member

Choose a reason for hiding this comment

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

I think the proper refactor would be to define the complete strings next to the constants, as a dense array of string constants (with NULL if some constant lacks a string). Probably, move EXPAND_COMMANDS etc enum from vim.c and command_complete array both to ex_cmds_defs.h. Compare to typedef enum hlf_T and hlf_names in highlight_defs.h. Maybe an accessor function should be used, to do bounds checking (negative index should return NULL string).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How about this possibility, for array command_complete, I add {INT_MIN, NULL} at the end, this element can be used to serve the end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You were asking for buffer?, means if negetive buffer number is sent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Didn't get it

Copy link
Member

Choose a reason for hiding this comment

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

It is used by ExpandGeneric which sorts the results anyway, so reordering them wouldn't be an issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, ExpandGeneric uses it, I also found it, so true, reordering is best way here

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 reorder them according to the value of the EXPAND_

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 sorted the list of commands according to the values of EXPAND_, now I want to test if it will be correct, will get_user_cmd_complete function pose no difficulty, where is its test

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorting the lines in reverse sorted is better, so then we have not to care for the 0 as the last element which acts as comparator for end, and also useful in binary search

// Address
for (j = 0; addr_type_complete[j].expand != -1; j++) {
if (addr_type_complete[j].expand != ADDR_LINES
&& addr_type_complete[j].expand == cmd->uc_addr_type) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here too is possibility

@nimitbhardwaj
Copy link
Contributor Author

I edited the array command_complete, this array is now sorted in descending order according to .expand (descending because, last element should be {0, NULL} so) and I add the binary search for case of calculating complete.
But this is under assumption that everything will be okay, no order specificness was there, if any error is encountered, I will try to fix it or in case of some misery, I will rollback this commit.
Please check it, its start, if needed, I can also replace linear search with bin search not a big deal

@bfredl
Copy link
Member

bfredl commented Feb 27, 2018

Sorry, but binary search of enum value in static array doesn't make any sense. Enum lookup array is both simpler and faster.

@nimitbhardwaj
Copy link
Contributor Author

Okk, but how about that function, that will not work, because loop is used there, what about it

@bfredl
Copy link
Member

bfredl commented Feb 27, 2018

what function?

@nimitbhardwaj
Copy link
Contributor Author

get_user_cmd_complete, I reordered the array, so it don't pose issue in the function.
So making lookup will be a difficulty in iterating the elements when ith one is needed

@bfredl
Copy link
Member

bfredl commented Feb 27, 2018

As I said on the line comment, that function can be supported by making the EXPAND_ kinds with a name first in the enum, then the NULL check in ExpandGeneric will work to get the right number of strings. The point of this refactor would be that it is both simpler and faster, while binary search of enum value adds more complexity for very small speed gain in not quite hot code path.

@nimitbhardwaj
Copy link
Contributor Author

I completely understand this, I didn't use much of lookup array in C before, it is C99 addition, now I am implementing it, yes, its easier.

@bfredl
Copy link
Member

bfredl commented Feb 27, 2018

The syntax might be new, but the pattern is not. For instance an "X macro" (with two args) could be used in older version on C to keep enum and string order matching.

@nimitbhardwaj
Copy link
Contributor Author

I made it, the lookup method, this works correctly, some mistakes may be there, some concept of NULL pointers, so I request for a review.

@@ -5815,7 +5815,7 @@ char_u *get_user_cmd_complete(expand_T *xp, int idx)
}
char *cmd_compl = get_command_complete(idx);
if (cmd_compl == NULL) {
return "\000";
Copy link
Member

Choose a reason for hiding this comment

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

just NULL. Thus the if can be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, in ExpandGeneric function, there is a check for NUL,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

as I investigated, NUL is '\000', so

Copy link
Contributor Author

Choose a reason for hiding this comment

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

which is same as "", thus made the small change

Copy link
Contributor Author

Choose a reason for hiding this comment

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

NUL and NULL are used differently

Copy link
Member

Choose a reason for hiding this comment

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

you're right, it should work.

case(EXTRA|NEEDARG): Arg[0] = '+'; break;
case(EXTRA|NOSPC|NEEDARG): Arg[0] = '1'; break;
}
PUT(dic, "argument", STRING_OBJ(cstr_to_string((const char *)Arg)));
Copy link
Member

Choose a reason for hiding this comment

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

"nargs"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okk

PUT(dic, "script_id", INTEGER_OBJ(cmd->uc_scriptID));

// Compl Arg
PUT(dic, "compl_arg",
Copy link
Member

Choose a reason for hiding this comment

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

this key should also only be present if the argument was not NULL. Also it could be called "complete_arg", and this code could be moved just below the "complete" code above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

for (j = 0; addr_type_complete[j].expand != -1; j++) {
if (addr_type_complete[j].expand != ADDR_LINES
&& addr_type_complete[j].expand == cmd->uc_addr_type) {
PUT(dic, "address",
Copy link
Member

Choose a reason for hiding this comment

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

"addr" (we typically prefer spelled out form when we add new keywords, but addr is already established in :command -addr)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok this is better

break;
}
}
if (!ck) {
Copy link
Member

Choose a reason for hiding this comment

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

can remove

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed


describe('get_commands', function()
local cmd_string = 'command Hello echo "Hello World"'
local cmd_string2 = 'command Pwd pwd'
Copy link
Member

Choose a reason for hiding this comment

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

Why not add a bit more attributes like complete,address etc here? (they don't need to make sense, just to exercise the code)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this too done, added 2 more tests for this, exploiting all features of command

@nimitbhardwaj
Copy link
Contributor Author

So I did it

@justinmk justinmk changed the title [RFC] Add the nvim_get_commands function [RFC] API: nvim_get_commands Mar 3, 2018
@justinmk justinmk mentioned this pull request Mar 3, 2018
@nimitbhardwaj nimitbhardwaj changed the title [RFC] API: nvim_get_commands [RFY] API: nvim_get_commands Mar 23, 2018
@nimitbhardwaj nimitbhardwaj changed the title [RFY] API: nvim_get_commands [RDY] API: nvim_get_commands Mar 23, 2018
@marvim marvim added RDY and removed RFC labels Mar 23, 2018
@justinmk justinmk added this to the 0.2.3 milestone Mar 26, 2018
@nimitbhardwaj
Copy link
Contributor Author

I rebased it too

@justinmk
Copy link
Member

Does this return builtin commands or only user-defined commands? If only user-defined commands, we should add a parameter to allow enhancement later without needing to add a new API function (or break the existing one; see :help api-contract). e.g.:

nvim_get_commands(Boolean builtin)

and only builtin=false is supported until future enhancement.

@nimitbhardwaj
Copy link
Contributor Author

It displays perhaps user defined commands, commands like echo, command, substitute etc are not displayed, so only the user defined commands are available, basically I used the output of the :command to generate the list.

And for the case of adding a parameter builtin I add it, and also I add a todo for it to create the support for the builtin commands in future, it presently only support the commands entered by the user, or commands declared with the command

@bfredl
Copy link
Member

bfredl commented Apr 15, 2018

An alternative is to later on include builtin commands in metadata. Yes, it is called "API metadata" for the moment, but I see no reason not to generalize it to other compile-time constant data of similar kind.

@nimitbhardwaj
Copy link
Contributor Author

nimitbhardwaj commented Apr 15, 2018

Yes, generalization of this seems messy, because I thought that there would be 3 options, so adding just boolean is not so good, 3 options are, builtin, user-def and both builtin and user-def.
I think there should firstly be the implementation to get the list of the builtin commands, then generalization would be much better.
How about this idea @justinmk and @bfredl, this is what I think about it
Otherwise adding a boolean is not so difficult, just I have to change its definations and some tests

@nimitbhardwaj
Copy link
Contributor Author

nimitbhardwaj commented Apr 15, 2018

Although I have done the changes, but I would like to add the builtinCommand_array() function in future

Please have a check if its correct.

@justinmk
Copy link
Member

For now, let it take a dictionary which currently is ignored:

nvim_get_commands(Dictionary opts)

Although I agree with @bfredl , I think we should plan to support returning builtin commands from nvim_get_command in the future, for "ergonomics".

@nimitbhardwaj
Copy link
Contributor Author

OK, we need to take the dictionary which will be ignored completely. I got it. The dictionary will hold the metadata in future, its good too.

@nimitbhardwaj
Copy link
Contributor Author

👍

@justinmk justinmk added the gsoc community: Google Summer of Code project label Apr 24, 2018
@justinmk justinmk mentioned this pull request May 10, 2018
@justinmk
Copy link
Member

Merged in #8375

@justinmk justinmk closed this May 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
gsoc community: Google Summer of Code project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants