0

Is there a way to detect incompatible snippet triggers?

Say:

snippet st "superscript" iA
<---snippet body--->
endsnippet

vs

snippet bst "binary spanning tree data" iA
<---snippet body--->
endsnippet

vs

snippet bs "basis information" iA
<---snippet body--->
endsnippet

Note, iA means the snippet will be expanded even in the inside of a word, automatically.

In the above case, bs would fire when bst is typed, so from the plugin POV there is no conflict, per se.

But from the user POV, bst will never fire. Is there a way to possibly call a function in UltiSnips that will detect and report such cases so that the user can choose the snippet triggers correctly without any conflict?

4
  • 1
    Perhaps :h UltiSnips#SnippetsInCurrentScope might be helpful
    – husB
    Commented Nov 23, 2022 at 15:06
  • @husB Thanks for the suggestion. That link seems to provide a function that I am having trouble understanding. I have a snippet called lp that is supposed to fire with options bA. So, in the beginning of the line, I typed l (in insert mode), went back to normal mode and then into command mode to issue :call UltiSnips#SnippetsInCurrentScope() but this gives rise to no noticeable effect. I expected that I get lp as a possible trigger word for some snippet. Perhaps I do not understand that documentation correctly.
    – Tryer
    Commented Nov 23, 2022 at 17:29
  • 1
    I believe your understanding is indeed correct. However, that function returns a dictionary, and doesn't explicitly print anything. Try :echo UltiSnips#SnippetsInCurrentScope() instead. Also, ensure that the cursor is to the right of l.
    – husB
    Commented Nov 24, 2022 at 3:46
  • 1
    Gotcha. What you suggested indeed worked. I had to type l p and then delete the space to get lp so that the snippet would not fire. Then, when I went into normal mode, the block cursor is on p of lp. Now issuing the echo command you suggested does indeed give me a list of snippets that start with l. So, all of the letters to the left of the current cursor position are taken as argument for the function.
    – Tryer
    Commented Nov 24, 2022 at 4:06

1 Answer 1

1

Below is a hackish solution for the problem. It is not an elegant solution. However, since apparently the question keeps getting bumped up to the top for lack of an accepted answer, I will accept my own answer so that everyone can sleep easier. :-)

In case there is an inbuilt solution or a better answer, please do contribute. Thank you.


One way to achieve this is the following.

Note that it is the snippets with A in their option list cause this problem. So, the following awk command processes the .snippets file and stores in a separate file the snippet triggers associated with option containing A:

awk '{if($1 == "snippet" && match($NF, "A"))printf ("%-50s\t%-d\n",$(2),NR)}' tex.snippets > keywords.txt

Then, it is a matter of processing these trigger keywords to see which pairs are subsets of each other. That can be accomplished via the following C++ code:

#include <string>
#include <vector>
#include <sstream>
#include <fstream>
std::vector<std::string> keywords;
std::vector<int> linenumbers;

// Returns -1 if s1 is not a substring of s2
int isSubstring(std::string s1, std::string s2)
{
    int M = s1.length();
    int N = s2.length();
  if (N < M)
    return -1;
    /* A loop to slide pat[] one by one */
    for (int i = 0; i <= N - M; i++) {
        int j;
        /* For current index i, check for
pattern match */
        for (j = 0; j < M; j++)
            if (s2[i + j] != s1[j])
                break;

        if (j == M)
            return i;
    }
    return -1;
}

int main() {
  std::ifstream ifile("keywords.txt");
  std::ofstream ofile("Processed_output.txt");
  std::string line;
  while (getline(ifile, line)) {
    std::istringstream ss(line);
      int lineno;
    while (!ss.eof()) {
      std::string hname;
      ss >> hname; 
      if (hname.length() > 0) {
        keywords.push_back(hname);
        ss >> lineno;
        linenumbers.push_back(lineno);
      }
    }
  }
  for (int i = 0; i < keywords.size(); i++) {
    for (int j = 0; j < keywords.size(); j++) {
      if (i == j)
        continue;
      if (isSubstring(keywords[i], keywords[j]) == -1) {
      }
      else {
        printf("Clash between %s [%d] and %s [%d]\n", keywords[i].c_str(), linenumbers[i], keywords[j].c_str(), linenumbers[j]);
        ofile << "Clash between " << keywords[i] << " ["<<linenumbers[i]<<"] and " << keywords[j] << " ["<<linenumbers[j]<<"]"<<std::endl; 
      }
    }
  }
  ifile.close();
  ofile.close();
}

This shows all the "clashes" for further analysis/correction.

7
  • Maybe you should accept your solution for clarity and to stop popping up for confirmation? Commented Dec 20, 2022 at 16:06
  • @VivianDeSmedt What? I haven't been in thread in a long time. What precisely is the issue that seems to irk you?
    – Tryer
    Commented Dec 20, 2022 at 16:31
  • Nothing important :-) It seems you have the solution to your problem. Maybe could you validate (accept via the green v) your solution. Commented Dec 20, 2022 at 17:12
  • I see. I usually do not have a practice to accept my own answers -- the present one seems hackish and I was hoping there is a better solution out there. I was under the impression that you were asking me to accept the answer because for some reason this question is "popping up for confirmation" ? I do not know what this means or why this happens? If no answer is accepted, is it a problem?
    – Tryer
    Commented Dec 20, 2022 at 17:16
  • Feel free to do what is best for you :-) Commented Dec 20, 2022 at 17:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.