1 /**
2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved.
3 License: MPL-2
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 This Source Code Form is subject to the terms of the Mozilla Public License,
7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain
8 one at http://mozilla.org/MPL/2.0/.
9 
10 This is a handy range to interate over either all files from the user OR all
11 files in a compilation database.
12 */
13 module dextool.user_filerange;
14 
15 import dextool.compilation_db : CompileCommandFilter, CompileCommandDB,
16     parseFlag;
17 import dextool.type : FileName, AbsolutePath;
18 
19 @safe:
20 
21 struct UserFileRange {
22     import std.typecons : Nullable;
23     import dextool.clang : findFlags;
24     import dextool.compilation_db : SearchResult;
25 
26     enum RangeOver {
27         inFiles,
28         database
29     }
30 
31     this(CompileCommandDB db, string[] in_files, string[] cflags,
32             const CompileCommandFilter ccFilter) {
33         this.db = db;
34         this.cflags = cflags;
35         this.ccFilter = ccFilter;
36         this.inFiles = in_files;
37 
38         if (in_files.length == 0) {
39             kind = RangeOver.database;
40         } else {
41             kind = RangeOver.inFiles;
42         }
43     }
44 
45     const RangeOver kind;
46     CompileCommandDB db;
47     string[] inFiles;
48     string[] cflags;
49     const CompileCommandFilter ccFilter;
50 
51     Nullable!SearchResult front() {
52         assert(!empty, "Can't get front of an empty range");
53 
54         Nullable!SearchResult curr;
55 
56         final switch (kind) {
57         case RangeOver.inFiles:
58             if (db.length > 0) {
59                 curr = db.findFlags(FileName(inFiles[0]), cflags, ccFilter);
60             } else {
61                 curr = SearchResult(cflags.dup, AbsolutePath(FileName(inFiles[0])));
62             }
63             break;
64         case RangeOver.database:
65             import std.array : appender;
66 
67             auto tmp = db.payload[0];
68             auto flags = appender!(string[])();
69             flags.put(cflags);
70             flags.put(tmp.parseFlag(ccFilter));
71             curr = SearchResult(flags.data, tmp.absoluteFile);
72             break;
73         }
74 
75         return curr;
76     }
77 
78     void popFront() {
79         assert(!empty, "Can't pop front of an empty range");
80 
81         final switch (kind) {
82         case RangeOver.inFiles:
83             inFiles = inFiles[1 .. $];
84             break;
85         case RangeOver.database:
86             db.payload = db.payload[1 .. $];
87             break;
88         }
89     }
90 
91     bool empty() @safe pure nothrow const @nogc {
92         final switch (kind) {
93         case RangeOver.inFiles:
94             return inFiles.length == 0;
95         case RangeOver.database:
96             return db.length == 0;
97         }
98     }
99 
100     size_t length() @safe pure nothrow const @nogc {
101         final switch (kind) {
102         case RangeOver.inFiles:
103             return inFiles.length;
104         case RangeOver.database:
105             return db.length;
106         }
107     }
108 }