Example #1
0
        private TaggedItem ParseLine(string[] prefixTags, string line, TaggedItem parent)
        {
            string bullet  = Regex.Match(line, "(^[\\*\\-\\+] )|(^\\d+\\. )").Value;
            string content = line.Substring(bullet.Length);

            (string[] Tags, string Remaining)tagContent = MDLineExtractTags(content);
            var newItem = new TaggedItem()
            {
                Content  = tagContent.Remaining,
                Tags     = prefixTags.Union(tagContent.Tags).Union(parent?.Tags ?? new string[] { }).Distinct().ToArray(),
                Children = null
            };

            if (parent != null)
            {
                if (parent.Children == null)
                {
                    parent.Children = new List <TaggedItem>();
                }
                parent.Children.Add(newItem);
                newItem.Parent = parent;
            }
            return(newItem);
        }
Example #2
0
        /// <summary>
        /// Parse a single markdown file as KMD - notice all markdowns are assumed KMD
        /// </summary>
        private KMDResource ParseMarkdown(string path, string[] fileTags)
        {
            // State preparation
            string filename = Path.GetFileNameWithoutExtension(path);

            PureFileNameExtractTags(filename, out filename);
            Stack <string[]> prefixTags = new Stack <string[]>();

            void ReinitializePrefixTags()
            {
                prefixTags.Clear();
                if (!filename.StartsWith('@'))
                {
                    prefixTags.Push(fileTags.Append(filename).ToArray());
                }
                else
                {
                    prefixTags.Push(fileTags);
                }
            }

            ReinitializePrefixTags();
            string            nextHeaderLevel = "#";
            List <TaggedItem> items           = new List <TaggedItem>();
            // Indetation status
            Stack <TaggedItem> parents            = new Stack <TaggedItem>();
            TaggedItem         current            = null;
            string             currentIndentation = "";
            // LFR resources
            bool   insideFileEndLFRSection = false;
            string lfrName = null;
            Dictionary <string, Fragment> fragments = new Dictionary <string, Fragment>();
            bool   insideCodeSection = false;
            string codeSectionMark   = null;

            // Enumerate lines
            foreach (var line in File.ReadAllLines(path))
            {
                if (!insideFileEndLFRSection)
                {
                    #region Regular Sections
                    // Collect list lines
                    // Todo: This is not considering cases where *-+ and numbers are mixed, pending
                    if (Regex.IsMatch(line, "(^[\\*\\-\\+] .*)|(^\\d+\\. .*)"))
                    {
                        // Clear indentation
                        parents.Clear();
                        ReinitializePrefixTags();
                        currentIndentation = "";
                        // Parse line
                        current = ParseLine(prefixTags.First(), line, null);
                        items.Add(current);
                    }
                    // Handle indentation
                    else if (Regex.IsMatch(line, "^\\s+(([\\*\\-\\+] .*)|(\\d+\\. .*))"))
                    {
                        if (parents.Count == 0 && current == null)
                        {
                            throw new ApplicationException($"Dangling sibling at line: `{line}`.");
                        }
                        string white      = Regex.Match(line, "^\\s*").Value;
                        string actualLine = line.Substring(white.Length);
                        // Normalize tab white
                        white = white.Replace("\t", "  ");
                        // Progress indentation
                        if (white.Length > currentIndentation.Length)
                        {
                            // Update indentation
                            currentIndentation = white;
                            parents.Push(current);
                            prefixTags.Push(current.Tags);
                            // Parse line
                            current = ParseLine(prefixTags.First(), actualLine, parents.First());
                        }
                        else if (white.Length == currentIndentation.Length)
                        {
                            current = ParseLine(prefixTags.First(), actualLine, parents.First());
                        }
                        // Revert indentation
                        else if (white.Length < currentIndentation.Length)
                        {
                            // Update indentation
                            currentIndentation = white;
                            parents.Pop();
                            prefixTags.Pop();
                            if (parents.Count == 0)
                            {
                                throw new ApplicationException($"Inconsistent indentation at line: `{line}`.");
                            }
                            // Parse line
                            current = ParseLine(prefixTags.First(), actualLine, parents.First());
                        }
                        items.Add(current);
                    }
                    // Special handle header
                    else if (line.StartsWith("# General Indexed Note") ||
                             line.StartsWith("# General Indexed Notes"))
                    {
                        continue;
                    }
                    else if (line.StartsWith("# Local Fragment Reference") ||
                             line.StartsWith("# Local Fragment References") ||
                             line.StartsWith("# LFR"))
                    {
                        insideFileEndLFRSection = true;
                    }
                    // Collect headers
                    else if (line.StartsWith(nextHeaderLevel))
                    {
                        prefixTags.Push(prefixTags.First().Append(line.Substring(nextHeaderLevel.Length + 1)).ToArray());
                        nextHeaderLevel += '#';
                    }
                    #endregion
                }
                else
                {
                    #region LFR
                    if (!insideCodeSection && line.StartsWith("## "))
                    {
                        lfrName = line.Substring("## ".Length);
                        // A resource that's not referenced
                        if (!fragments.ContainsKey(lfrName))
                        {
                            fragments[lfrName] = new Fragment(lfrName, string.Empty, null);
                        }
                        continue;
                    }
                    else if (line.StartsWith("```"))
                    {
                        if (insideCodeSection)
                        {
                            insideCodeSection = false;
                            codeSectionMark   = null;
                        }
                        else
                        {
                            insideCodeSection = true;
                            codeSectionMark   = Regex.Match(line, "^(`+).*").Groups[1].Value;
                        }
                    }
                    if (lfrName != null)
                    {
                        fragments[lfrName].Content += line + '\n';
                    }
                    #endregion
                }
            }
            // Connect fragments with items
            ConnectFragments(items, fragments);
            return(new KMDResource(items, fragments));
        }
Example #3
0
        private static string ReproduceContent(string originalReference, List <TaggedItem> filteredResult)
        {
            // Get largest comment set to reduce repeating items
            string[] commonTags = filteredResult.Count > 1 ? filteredResult.SelectMany(r => r.Tags).Distinct().ToArray() : new string[] { };
            filteredResult.ForEach(r => commonTags = commonTags.Intersect(r.Tags).ToArray());

            // Generate output
            StringBuilder builder = new StringBuilder($"# Indexed Notes ({string.Join(", ", commonTags)})\n\n");

            // Iterate and show items in hierarchical fashion
            Stack <TaggedItem> last = new Stack <TaggedItem>();

            for (int i = 0; i < filteredResult.Count; i++)
            {
                TaggedItem item = filteredResult[i];
                // Root
                if (item.Parent == null || !filteredResult.Contains(item.Parent))
                {
                    last.Clear();
                    string tagString = string.Join(", ", item.Tags);
                    tagString = string.IsNullOrEmpty(tagString) ? string.Empty : $"({tagString}) ";
                    string formatted = $"* {tagString}{item.Content} " +
                                       $"<!-- {item.Children?.Count ?? 0} children; Is {(item.Parent == null ? "not " : "")}a child";
                    builder.Append(formatted);
                }
                // Children
                else
                {
                    if (last.Count == 0)
                    {
                        last.Push(item.Parent);
                    }
                    else if (item.Parent != last.First())
                    {
                        if (last.Contains(item.Parent))
                        {
                            last.Pop();
                        }
                        else
                        {
                            last.Push(item.Parent);
                        }
                    }
                    string tagString = string.Join(", ", item.Tags.Except(commonTags).Except(item.Parent.Tags));
                    tagString = string.IsNullOrEmpty(tagString) ? string.Empty : $"**({tagString})** ";
                    string formatted = $"{new string('\t', last.Count)}* {tagString}{item.Content} " +
                                       $"*{item.Children?.Count ?? 0} children; Is {(item.Parent == null ? "not " : "")}a child";
                    builder.Append(formatted);
                }
                // Line number
                int number = originalReference.Substring(0, originalReference.IndexOf(item.Content)).Where(c => c == '\n').Count() + 1;
                builder.Append($" - Line Number: {number} -->");
                builder.Append("\n");
            }
            builder.AppendLine("\n");

            // Fragments
            var fragments = filteredResult.SelectMany(f => f.References ?? new List <Fragment>()).Distinct();

            builder.AppendLine("# LFR\n");
            foreach (var f in fragments)
            {
                builder.AppendLine($"## {f.Name}");
                builder.AppendLine();
                builder.AppendLine(f.Content.Trim());
                builder.AppendLine();
            }

            return(builder.ToString());
        }