# -*- coding: utf-8 -*-
"""
Copyright (C) 2011 Oliver Tengler
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from typing import Optional, List, Tuple
from fnmatch import fnmatch
import unittest
from tools import Config
class ExtensionMapping:
def __init__(self, extPattern: str, configFile: str) -> None:
# The significance is the number of none wildcard chars. E.g. CPP has a significance of 3, C* has only 1.
self.significance = sum ((lambda c: c!="*" and c!="?")(c) for c in extPattern)
# A pattern which matches the extension
self.extPattern = extPattern
self.configFile = configFile
def match (self, ext: str) -> int:
"""Returns the significance if the configuration matches the pattern , -1 otherwise"""
if ext.startswith("."):
ext = ext[1:]
if fnmatch (ext, self.extPattern):
return self.significance
return -1
class Highlighter:
"""
Contains a list of ExtensionMapping objects. Its main function is to lookup the right ExtensionMapping for
a given extension.
"""
def __init__(self, conf: Config.Config) -> None:
self.mappings = self.readConfig (conf)
def readConfig (self, conf: Config.Config) -> List[ExtensionMapping]:
"""
Highlighter_Default {
config = C++.txt
extensions = *
}
"""
mappings: List[ExtensionMapping] = []
for c in conf:
if c.startswith("highlighter"):
settings = conf[c]
extensions = settings.extensions
configFile = settings.config
for pattern in extensions.split(","):
mappings.append(ExtensionMapping(pattern, configFile))
return mappings
def lookup (self, ext: str) -> Optional[str]:
"""Lookup highlighter config file by extension"""
matches: List[Tuple[int, ExtensionMapping]] = []
for mapping in self.mappings:
significance = mapping.match(ext)
if significance != -1:
matches.append((significance, mapping))
# Sort by significance
matches.sort(key=lambda i: i[0], reverse=True)
if matches:
return matches[0][1].configFile
return None
class HighlighterCache:
highlighter: Optional[Highlighter] = None
def highlighter(conf: Config.Config) -> Highlighter:
if not HighlighterCache.highlighter:
HighlighterCache.highlighter = Highlighter(conf)
return HighlighterCache.highlighter
#Highlighter_Default {
# config = default.txt
# extensions = *
#}
#
#Highlighter_C {
# config = C.txt
# extensions = c*,h*,inl
#}
#
#Highlighter_CPP {
# config = C++.txt
# extensions = cpp
#}
class TestHighlighterConfig(unittest.TestCase):
def test(self) -> None:
h = highlighter(Config.Config("tests\\SourceViewer.txt"))
self.assertEqual (h.lookup("py"), "default.txt")
self.assertEqual (h.lookup("cpp"), "C++.txt")
self.assertEqual (h.lookup("CPP"), "C++.txt")
self.assertEqual (h.lookup("c"), "C.txt")
self.assertEqual (h.lookup("c"), "C.txt")
if __name__ == "__main__":
unittest.main()