private static List<CompletionItem> getMacroCompletion(
     int startOffset, int caretOffset, String filter) {
   List<CompletionItem> list = new ArrayList<CompletionItem>();
   for (LatteMacro macro : MacroDefinitions.macros) {
     if (macro.getMacro().startsWith(filter)) {
       list.add(new LatteCompletionItem(macro, startOffset, caretOffset));
     }
   }
   return list;
 }
  private static List<CompletionItem> getNTagCompletion(
      int startOffset, int caretOffset, String filter) {
    List<CompletionItem> list = new ArrayList<CompletionItem>();

    if (!filter.startsWith("<n:")) {
      return list;
    }

    for (LatteMacro macro : MacroDefinitions.macros) {
      boolean hasParam = MacroDefinitions.tagMacros.containsKey(macro.getMacroName());
      if ((macro.getClass() == LatteMacro.class || hasParam)
          && Character.isLetter(macro.getMacroName().charAt(0))) {
        String name = macro.getMacroName();
        if (("<n:" + name).startsWith(filter)) {
          if (!hasParam) {
            list.add(
                new MacroCompletionItem(
                    "<n:" + name, startOffset, caretOffset, true, name.length() + 3));
          } else {
            String tag = "<n:" + name;
            for (String s : MacroDefinitions.tagMacros.get(macro.getMacroName())) {
              tag += " " + s + "=\"\"";
            }
            list.add(
                new MacroCompletionItem(tag, startOffset, caretOffset, true, tag.length() - 1));
          }
        }
      }
    }
    return list;
  }
  private static List<CompletionItem> getNAttributeCompletion(
      int startOffset, int caretOffset, String filter) {
    List<CompletionItem> list = new ArrayList<CompletionItem>();

    if (!filter.startsWith("n:")) {
      return list;
    }

    for (LatteMacro macro : MacroDefinitions.macros) {
      if (!(macro instanceof LatteParamMacro) || !macro.isPair()) {
        continue;
      }
      String name = macro.getMacroName();
      String tag = "n:" + name;
      if (tag.startsWith(filter)) {
        list.add(new MacroCompletionItem(tag, startOffset, caretOffset, true));
      }
      tag = "n:inner-" + name;
      if (tag.startsWith(filter)) {
        list.add(new MacroCompletionItem(tag, startOffset, caretOffset, true));
      }
      tag = "n:tag-" + name;
      if (tag.startsWith(filter)) {
        list.add(new MacroCompletionItem(tag, startOffset, caretOffset, true));
      }
    }

    for (LatteMacro macro : MacroDefinitions.nAttrs) {
      String tag = "n:" + macro.getMacroName();
      if (tag.startsWith(filter)) {
        list.add(new MacroCompletionItem(tag, startOffset, caretOffset, true));
      }
    }

    return list;
  }
  private static List<CompletionItem> getFriendMacroCompletion(
      List<LatteMacro> endMacros, int startOffset, int caretOffset, String filter) {

    List<CompletionItem> list = new ArrayList<CompletionItem>();
    for (LatteMacro macro : endMacros) {
      String m = macro.isPair() ? macro.getEndMacro() : macro.getMacro();
      if (macro.isPair()) {
        macro = new LatteMacro("/" + macro.getEndMacroName());
      }
      if (m.startsWith(filter)) {
        list.add(new LatteCompletionItem(macro, startOffset, caretOffset));
      }
    }
    return list;
  }