Skip to content

Commit e4cfb63

Browse files
authored
Merge pull request #15 from FontysVenlo/improve-comments
Improve comments
2 parents fd2a915 + 80b2cd7 commit e4cfb63

23 files changed

Lines changed: 172 additions & 62 deletions

codestripper/cli.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ def add_commandline_arguments(parser: argparse.ArgumentParser) -> None:
1313
# Add optional arguments
1414
parser.add_argument("-x", "--exclude", action="append",
1515
help="files to include for code stripping (glob)", default=[])
16-
parser.add_argument("-c", "--comment", action="store",
17-
help="comment symbol(s) for the given language", default="//")
16+
parser.add_argument("-c", "--comment", action="append",
17+
help="comment symbol(s) for the given language, usage: <extension>:<comment> (e.g. .java://")
1818
parser.add_argument("-v", "--verbosity", action="count", help="increase output verbosity", default=0)
1919
parser.add_argument("-o", "--output", action="store",
2020
help="output directory to store the stripped files", default="out")
@@ -44,4 +44,6 @@ def main() -> None:
4444
cwd = get_working_directory(args.working_directory)
4545
files = FileUtils(args.include, args.exclude, cwd, args.recursive, logger_name).get_matching_files()
4646
# Strip all the files
47-
strip_files(files, cwd, args.comment, args.output, args.dry_run, args.fail_on_error)
47+
48+
strip_files(files, cwd, comments=args.comment, output=args.output, dry_run=args.dry_run,
49+
fail_on_error=args.fail_on_error)

codestripper/code_stripper.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,29 @@
22
import os.path
33
import shutil
44
from pathlib import Path
5-
from typing import Union, Iterable, List
5+
from typing import Union, Iterable, List, Optional
66

77
from codestripper.errors import InvalidTagError, TokenizerError
88
from codestripper.tags import IgnoreFileError
99
from codestripper.tags.tag import Tag, RangeTag
1010
from codestripper.tokenizer import Tokenizer
1111
from codestripper.utils import get_working_directory
12+
from codestripper.utils.comments import comments_mapping, Comment
1213

1314
logger = logging.getLogger("codestripper")
1415

1516

16-
def strip_files(files: Iterable[str], working_directory: Union[str, None] = None, comment: str = "//",
17+
def strip_files(files: Iterable[str], working_directory: Union[str, None] = None, * ,comments: Optional[List[str]] = None,
1718
output: Union[Path, str] = "out", dry_run: bool = False, fail_on_error: bool = False) -> List[str]:
19+
20+
if comments is not None:
21+
for comment in comments:
22+
parts = comment.split(":")
23+
if len(parts) == 2:
24+
comments_mapping[parts[0]] = Comment(parts[1])
25+
else:
26+
comments_mapping[parts[0]] = Comment(parts[1], parts[2])
27+
1828
cwd = get_working_directory(working_directory)
1929
out = os.path.join(os.getcwd(), output)
2030
if os.path.isdir(out):
@@ -26,7 +36,14 @@ def strip_files(files: Iterable[str], working_directory: Union[str, None] = None
2636
content = handle.read()
2737
if content is not None:
2838
try:
29-
stripped = CodeStripper(content, comment).strip()
39+
_, file_extension = os.path.splitext(file)
40+
file_extension = file_extension.lower()
41+
if not file_extension in comments_mapping:
42+
logger.error(f"Unknown extension: '{file_extension}', "
43+
f"please specify which comment to use for this file extension.")
44+
continue
45+
com = comments_mapping[file_extension]
46+
stripped = CodeStripper(content, com).strip()
3047
except IgnoreFileError:
3148
logger.info(f"File '{file}' is ignored, because of ignore tag")
3249
continue
@@ -50,7 +67,7 @@ def strip_files(files: Iterable[str], working_directory: Union[str, None] = None
5067

5168
class CodeStripper:
5269

53-
def __init__(self, content: str, comment: str) -> None:
70+
def __init__(self, content: str, comment: Comment) -> None:
5471
self.content = content
5572
self.comment = comment
5673

codestripper/tags/add.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55

66
class AddTag(SingleTag):
7-
regex = r'cs:add:(.*?)$'
7+
regex = r'cs:add:(.*)?'
88

99
def __init__(self, data: TagData) -> None:
1010
super().__init__(data)

codestripper/tags/legacy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55

66
class LegacyOpenTag(RangeOpenTag):
7-
regex = r'Start Solution::replacewith::(.*?)$'
7+
regex = r'Start Solution::replacewith::(.*)'
88

99
def __init__(self, data: TagData) -> None:
1010
super().__init__(LegacyRangeTag, data)
@@ -20,7 +20,7 @@ def execute(self, content: str) -> Union[str, None]:
2020

2121

2222
class LegacyCloseTag(RangeCloseTag):
23-
regex = r'End Solution::replacewith::(.*?)$'
23+
regex = r'End Solution::replacewith::(.*)'
2424

2525
def __init__(self, data: TagData) -> None:
2626
super().__init__(LegacyRangeTag, data)

codestripper/tags/remove.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
class RemoveTag(SingleTag):
55

6-
regex = r'cs:remove\s*?$'
6+
regex = r'cs:remove(?!:)(.*)?'
77

88
def __init__(self, data: TagData):
99
super().__init__(data)

codestripper/tags/replace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

44
class ReplaceTag(SingleTag):
5-
regex = r'cs:replace:(.*?)$'
5+
regex = r'cs:replace:(.*?)'
66

77
def __init__(self, data: TagData) -> None:
88
super().__init__(data)

codestripper/tags/tag.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from dataclasses import dataclass
33
from typing import Type, Union, List, Pattern, Iterable, Optional
44

5+
from codestripper.utils.comments import Comment
6+
57

68
@dataclass
79
class TagData:
@@ -13,7 +15,7 @@ class TagData:
1315
regex_end: int
1416
parameter_start: int
1517
parameter_end: int
16-
comment: str
18+
comment: Comment
1719

1820
def __repr__(self) -> str:
1921
return (f"{self.line}, line ({self.line_number}): {self.line_start}:{self.line_end},"

codestripper/tags/uncomment.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55

66

77
class UncommentOpenTag(RangeOpenTag):
8-
regex = r'cs:uncomment:start.*?$'
8+
regex = r'cs:uncomment:start(.*)?'
99

1010
def __init__(self, data: TagData) -> None:
1111
super().__init__(UncommentRangeTag, data)
1212

1313

1414
class UncommentCloseTag(RangeCloseTag):
15-
regex = 'cs:uncomment:end.*?$'
15+
regex = 'cs:uncomment:end(.*)?'
1616

1717
def __init__(self, data: TagData) -> None:
1818
super().__init__(UncommentRangeTag, data)
@@ -27,7 +27,7 @@ def __init__(self, open_tag: RangeOpenTag, close_tag: RangeCloseTag):
2727
def execute(self, content: str) -> Union[str, None]:
2828
if UncommentRangeTag.regex is None:
2929
whitespace = r"(?P<whitespace>\s*)"
30-
UncommentRangeTag.regex = re.compile(f"{whitespace}{self.open_tag.data.comment}")
30+
UncommentRangeTag.regex = re.compile(f"{whitespace}{self.open_tag.data.comment.open}")
3131
range = content[self.start:self.end]
3232
replacement = UncommentRangeTag.regex.sub(r"\g<whitespace>", range)
3333
return replacement

codestripper/tokenizer.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from codestripper.tags import ReplaceTag, UncommentCloseTag, IgnoreFileTag, RemoveOpenTag, RemoveCloseTag, \
66
UncommentOpenTag, LegacyOpenTag, LegacyCloseTag, RemoveTag, AddTag
77
from codestripper.tags.tag import SingleTag, Tag, RangeOpenTag, RangeCloseTag, RangeTag, TagData
8+
from codestripper.utils.comments import Comment
89

910
default_tags: Set[Type[SingleTag]] = {
1011
IgnoreFileTag,
@@ -25,30 +26,36 @@
2526
CreateTagMapping = Dict[str, CreateTagLambda]
2627

2728

28-
def calculate_mappings(tags: Set[Type[SingleTag]], comment: str) -> Tuple[CreateTagMapping, Pattern]:
29+
def calculate_mappings(tags: Set[Type[SingleTag]], comment: Comment) -> Tuple[CreateTagMapping, Pattern]:
2930
strings = [r"(?P<newline>\n)"]
3031
mappings = {}
3132
for tag in tags:
3233
name = f"{tag.__name__}"
3334
mappings[name] = lambda data, constructor=tag: constructor(data)
34-
strings.append(f"(?P<{name}>{comment}{tag.regex})")
35+
reg = f"(?P<{name}>{re.escape(comment.open)}{tag.regex})"
36+
if comment.close is not None:
37+
reg += re.escape(comment.close)
38+
strings.append(reg)
3539
regex = re.compile("|".join(strings), flags=re.MULTILINE)
3640
return mappings, regex # type: ignore
3741

3842

3943
class Tokenizer:
44+
mapping_cache: Dict[str, Tuple[CreateTagMapping, Pattern]] = {}
4045
mappings: CreateTagMapping = {}
4146
regex: Pattern = re.compile("")
42-
comment: str = ""
47+
comment: Comment
4348

44-
def __init__(self, content: str, comment: str) -> None:
49+
def __init__(self, content: str, comment: Comment) -> None:
4550
self.content = content
4651
self.ordered_tags: List[Tag] = []
4752
self.open_stack: List[RangeOpenTag] = []
4853
self.range_stack: Dict[int, Optional[List[Tag]]] = {}
49-
if len(Tokenizer.mappings) == 0 or Tokenizer.comment != comment:
50-
Tokenizer.mappings, Tokenizer.regex = calculate_mappings(default_tags, comment)
51-
Tokenizer.comment = comment
54+
Tokenizer.comment = comment
55+
if not str(comment) in Tokenizer.mapping_cache:
56+
Tokenizer.mapping_cache[str(comment)] = calculate_mappings(default_tags, comment)
57+
Tokenizer.mappings = Tokenizer.mapping_cache[str(comment)][0]
58+
Tokenizer.regex = Tokenizer.mapping_cache[str(comment)][1]
5259
self.group_count = self.regex.groups
5360

5461
def tokenize(self) -> List[Tag]:

codestripper/utils/comments.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from dataclasses import dataclass
2+
from typing import Optional, Dict
3+
4+
5+
@dataclass(frozen=True)
6+
class Comment:
7+
open: str
8+
close: Optional[str] = None
9+
10+
comments_mapping: Dict[str, Comment] = {
11+
".java": Comment("//"),
12+
".cs": Comment("//"),
13+
".js": Comment("//"),
14+
".php": Comment("//"),
15+
".swift": Comment("//"),
16+
".xml": Comment("<!--", "-->"),
17+
".tex": Comment("%"),
18+
".m": Comment("%"),
19+
".sql": Comment("--"),
20+
".lua": Comment("--"),
21+
".ml": Comment("(*", "*)"),
22+
".r": Comment("#"),
23+
".py": Comment("#"),
24+
".ps1": Comment("#"),
25+
".rb": Comment("#")
26+
}

0 commit comments

Comments
 (0)