xeluxee / competitest.nvim

CompetiTest.nvim is a Neovim plugin for Competitive Programming: it can manage and check testcases, download problems and contests from online judges and much more
GNU Lesser General Public License v3.0
381 stars 15 forks source link

Add options to enable fixed folder structure for received problems and contest #40

Closed xeluxee closed 11 months ago

xeluxee commented 1 year ago

This should fix #28, #29 and #32

@ayham-1 @MuhammadSawalhy @vishalpaudel I need your feedback, please.

This PR adds 2 new options, received_problems_directory and received_contests_directory, they're both configured the same way:

Available receive-modifiers: modifier meaning
$() insert dollar
$(HOME) home directory
$(PROBLEM) Problem name, name field
$(GROUP) judge and contest name, group field
$(JUDGE) first part of group, before hyphen
$(CONTEST) second part of group, after hyphen
$(URL) problem url, url field
$(MEMLIM) available memory, memoryLimit field
$(TIMELIM) time limit, timeLimit field

$(DATE) will be implemented later, along with #39

MuhammadSawalhy commented 1 year ago

I notice a wrong directory when trying to receive this problem with:

received_problems_directory = "$(HOME)/myp/problem-solving/$(JUDGE)/$(CONTEST)/"

image

It should be /Virtual Judge/HackerRank. Here is the JSON received from Competitive Companion:

{
    "name": "Easy Addition",
    "group": "Virtual Judge - HackerRank",
    "url": "https://vjudge.net/problem/HackerRank-easy-addition",
    "interactive": false,
    "memoryLimit": 1024,
    "timeLimit": 1000,
    "tests": [
        {
            "input": "a1 d1 a2 d2 A B\n",
            "output": "i j\n"
        },
        {
            "input": "7 2\n1 2\n1 3\n2 4\n2 6\n4 5\n6 7\n1 4\n1 1 1 1 4 6\n4 5\n2 7\n4 7\n5 3\n",
            "output": "1\n44\n45\n9\n"
        }
    ],
    "testType": "single",
    "input": {
        "type": "stdin"
    },
    "output": {
        "type": "stdout"
    },
    "languages": {
        "java": {
            "mainClass": "Main",
            "taskClass": "EasyAddition"
        }
    },
    "batch": {
        "id": "2c77d6ac-232c-4c56-987b-b8f366419edb",
        "size": 1
    }
}
MuhammadSawalhy commented 1 year ago

No prompt

I think when received_problems_directory is set, there is no need to display a prompt for the problem directory. And when the default language of the template is set, there is no need to prompt for the language.

Open the file

When the problem is received and the file is created from the template, the created file should be automatically opened. This behaviour exists in the CPH VSCode plugin.

Cancel receiving

Like how the telescope window works and how the picker UI work, to cancel receiving a problem or a contest by just pressing ESC in INSERT mode. We can cancel with ctrl+c but it is not intuitive and not documented in the README. The test cases editor can be cancelled with q in NORMAL mode and ctrl+q in INSERT mode. Should the default configuration be consistent and use the same keybindings in INSERT and NORMAL for all windows created by this plugin? Can you make the prompt window of problems and contests directory configurable like other windows?

xeluxee commented 1 year ago

It should be /Virtual Judge/HackerRank. Here is the JSON received from Competitive Companion

Thanks, fixed.

When the problem is received and the file is created from the template, the created file should be automatically opened. This behaviour exists in the CPH VSCode plugin

I'll add an option for that.

Like how the telescope window works and how the picker UI work, to cancel receiving a problem or a contest by just pressing ESC in INSERT mode

By default telescope maps <C-c> to close window, <esc> to switch to normal mode. Normal mode is still relevant for input popup, e.g. to edit a longer prompt. Anyway I'll make insert and normal mode mappings configurable.

MuhammadSawalhy commented 1 year ago

By default telescope maps <C-c> to close window

Ok ESC in NORMAL mode may not be a good idea, but what about consistency? Why is ctrl+q used to close the test cases editor and ctrl+c is used to close the problem directory prompt?

xeluxee commented 1 year ago

I've added 5 options:

xeluxee commented 1 year ago

Why is ctrl+q used to close the test cases editor and ctrl+c is used to close the problem directory prompt?

<C-c> is the default close keymap in nui input popup. As already said, I'll make insert and normal mode mappings configurable.

MuhammadSawalhy commented 1 year ago

Great! :heart:

MuhammadSawalhy commented 1 year ago

I've just noticed this data received from CompetitiveCompanion, the Java class name which must be the same. Can you add some modifiers for the template?

{
    "languages": {
        "java": {
            "mainClass": "Main",
            "taskClass": "EasyAddition"
        }
    }
}

If some modifiers are available for the templates we can do something like this:

// This is java template

public class $(JAVA_CLASS_NAME) {
   public static void main(String[] args) {
   }
}
// This is a cpp file
// I am solving: $(PROBLEM)
// $(CONTEST) --- $(JUDGE) 

#include <stdio>
using namespace std;

int main() {
  return 0;
}
MuhammadSawalhy commented 1 year ago

In the case of Java the file name must match the class name, so is it better to configure the filename rather than the file directory? Should we not care about another option to configure the contests directory and treat each problem of the contest as if it is received alone?!

This can also be useful in some use cases like:

received_problem_filename = "$(HOME)/path/to/$(JUDGE)/$(CONTEST)/$(PROBLEM)/main.$(FEXT)"

Update:

I noticed that to handle the Java use case, the plugin should prompt (if no default language is specified) for the language (file extension) first then the file name will be specified. A possible function for received_problem_filename will be:

 function(problem, group, url, language, java_class_name)
    local hyphen = string.find(group, " - ", 1, true)
    local judge, contest

    if not hyphen then
        judge = group
        contest = "unknown_contest"
    else
        judge = string.sub(group, 1, hyphen - 1)
        contest = string.sub(group, hyphen + 3)
    end

        if language == "java" then
        return string.format("%s/problems/%s/%s/%s/%s.java", vim.loop.os_homedir(), judge, contest, problem, java_class_name)
    else
        return string.format("%s/problems/%s/%s/%s/main.%s", vim.loop.os_homedir(), judge, contest, problem, language)
    end
end

But I suggest instead of sending many arguments to the function, it can get the received problem from CompetitiveCompanion as a table in Lua, so the function can get any information possible about the problem.

xeluxee commented 1 year ago

I've just noticed this data received from CompetitiveCompanion, the java class name which must be the same. Can you make add some modifiers for the template?

I can add $(JAVA_MAIN_CLASS) and $(JAVA_TASK_CLASS) modifiers.

In the case of Java the file name must match the class name, so is it better to configure the filename rather than the file directory? Should we not care about another option to configure the contests directory and treat each problem of the contest as if it is received alone?!

Yes, we can configure filename rather than directory for received problems. So we need $(CWD) and $(FEXT) modifiers. What about an option received_problems_path, that can be configured as follows:

By default it's a string, $(CWD)/$(PROBLEM).$(FEXT). Then I can rename received_problems_prompt_filename to received_problems_prompt_path, so users can decide whether to see prompt or not.

But I suggest instead of sending many arguments to the function, it can get the received problem from CompetitiveCompanion as a table in Lua, so the function can get any information possible about the problem.

Right.

xeluxee commented 1 year ago

In the case of Java the file name must match the class name, so is it better to configure the filename rather than the file directory? Should we not care about another option to configure the contests directory and treat each problem of the contest as if it is received alone?!

Yes, we can configure filename rather than directory for received problems. So we need $(CWD) and $(FEXT) modifiers. What about an option received_problems_path, that can be configured as follows:

  • string: $(HOME)/Competitive Programming/$(JUDGE)/$(CONTEST)/$(PROBLEM).$(FEXT)

  • function accepting task and file extension as arguments, returning absolute file path

By default it's a string, $(CWD)/$(PROBLEM).$(FEXT). Then I can rename received_problems_prompt_filename to received_problems_prompt_path, so users can decide whether to see prompt or not.

It's better to not do the same for contests, and use 4 options instead:

A single option with full file path for contests is not prompt-friendly, since it would require users to see a prompt for each problem. This way users can see at most two prompts when receiving a contest, one for contest root directory and another one for file extension.

[^1]: the modifier JAVA_TASK_CLASS is generated from problem name removing all non-alphabetic or non-numeric characters, including spaces and punctuation. As competitive companion README states: "The classname-friendly version of the problem's full name. Cannot be the same as mainClass. Can also be useful for non-Java tools because a classname-friendly string is also a filename-friendly string"

MuhammadSawalhy commented 12 months ago

My preference for this is to make it simple and configure only the path of the received problem and when a user tries to receive a contest the plugin will create a file for each problem using received_problems_path. But if you see that we need a separate option to configure the path of the received contest, you can consider received_contest_problem_path to configure that path of the problem, not a directory for the problems.

Or a better way to pass another boolean argument to the function of received_problems_path that indicates whether the plugin is receiving a contest or a problem.

The more options to configure the more complicated the plugin will be and the more bloated the README will be.

xeluxee commented 12 months ago

But if you see that we need a separate option to configure the path of the received contest, you can consider received_contest_problem_path to configure that path of the problem, not a directory for the problems.

I know that using an option similar to received_problems_path (i.e. full path and not directory) would make configuration more consistent, but splitting the path into two options (one for root directory and one for relative path) is necessary for users who prefer being asked for contest root directory with a prompt, otherwise they'd need to see a prompt for each received problem.

The more options to configure the more complicated the plugin will be and the more bloated the README will be

I'm planning to introduce these options with this PR (some of them are already implemented):

README is already bloated, as soon as possible I'll move configuration section to another file or to proper vimdoc. These options look reasonable to me.

MuhammadSawalhy commented 12 months ago

is necessary for users who prefer being asked for contest root directory with a prompt, otherwise they'd need to see a prompt for each received problem.

Great, You convinced me!

xeluxee commented 12 months ago

I'm planning to introduce these options with this PR (some of them are already implemented):

  • received_files_extension: string
  • open_received_problems: boolean
  • open_received_contests: boolean
  • received_problems_path: string or function
  • received_problems_prompt_path: boolean
  • received_contests_directory: string or function
  • received_contests_problems_path: string or function
  • received_contests_prompt_directory: boolean
  • received_contests_prompt_extension: boolean

@MuhammadSawalhy take a look at latest commit, I've implemented all the above options. We'll take care of adding options for configuring input prompt in another PR.

xeluxee commented 12 months ago

I've just updated README, this PR is ready to be merged