Example #1
0
    def print_note_listing(self, notepaths):
        """
        Print a list of note in a nicely formatted way.

        Parameter
        ---------
        notepaths : list
            A list of filepaths of notes.
        """

        # fmt is of the form:
        # <index>    YYYY-MM-DD aaa    <title>
        fmt = '{:>4}    {:<14}    {}'
        N = len(notepaths)

        # If note_list is empty, do not print anything
        if N == 0:
            return None
        else:
            print()
        #     print(fmt.format('index', 'date', 'title'))

        for i, notepath in enumerate(notepaths):
            note = parse_note(notepath)
            print(fmt.format(str(N - 1 - i), note.creation_date, note.title))
            # Flush stdout after each print statement so that the listing
            # appears smooth to the user:
            sys.stdout.flush()

        self.history.append(notepaths)
        infobar = '\nlisting: {}\ttotal: {}'.format(len(self.history), N)
        print(infobar)
Example #2
0
 def build_index(self):
     self.index = defaultdict(set)
     for notepath in glob.glob(self.notepath_pattern):
         _, _, _, note_id = extract_filename_info(notepath)
         note = parse_note(notepath) 
         for tag in note.tags:
             self.index[tag].add(note_id)
     self.save_index()
Example #3
0
def test_parse_note():
    notepath = os.path.join(root, 'notes', '2015-08-02-2-2015-01-12.txt')
    note = parse_note(notepath)
    assert note.filepath == notepath
    assert note.creation_date == '2015-08-02 Sun'
    assert note.modification_date == '2015-01-12 Mon'
    assert note.title == 'Title'
    assert note.body == 'Body'
    assert note.tags == ['tag1', 'tag2']
Example #4
0
File: ui.py Project: kalleroska/poi
def delete_note(args):
    """
    Delete a given note.
    """
    notepath = parse_index(args)
    if notepath is None:
        return None
    note = parse_note(notepath)
    print(note.creation_date, '   ', note.title)
    ans = confirm('delete? (y/n) ')
    if ans:
        nm.delete_note(notepath)
Example #5
0
 def describe_note(self, notepath):
     note = parse_note(notepath)
     tokens = []
     tokens.append((Token.Attribute, '{:>20}'.format('title: ')))
     tokens.append((Token.Value, note.title + '\n'))
     tokens.append((Token.Attribute, '{:>20}'.format('date: ')))
     tokens.append((Token.Value, note.creation_date + '\n'))
     tokens.append((Token.Attribute, '{:>20}'.format('last modified: ')))
     tokens.append((Token.Value, note.modification_date + '\n'))
     tokens.append((Token.Attribute, '{:>20}'.format('tags: ')))
     tokens.append((Token.Value, ', '.join(note.tags) + '\n'))
     tokens.append((Token.Attribute, '{:>20}'.format('number of links: ')))
     tokens.append((Token.Value, str(len(note.links)) + '\n'))
     tokens.append((Token.Attribute, '{:>20}'.format('filepath: ')))
     tokens.append((Token.Value, note.filepath + '\n'))
     tokens.append((Token.Attribute, '{:>20}'.format('identifier: ')))
     tokens.append((Token.Value, note.identifier + '\n'))
     print_tokens(tokens, style=self.color_style)
Example #6
0
    def update_index(self):
        """
        Parameter
        ---------
        date : str
            Of form YYYY-MM-DD. Only notes whose modification is greater than
            or equal to this date will be considered when the index is updated.
        """

        # Get the last update date:
        t = os.path.getmtime(self.filepath)
        d = datetime.datetime.fromtimestamp(t)
        date =  d.strftime('%Y-%m-%d')

        for notepath in glob.glob(self.notepath_pattern):
            _, m_date, _, note_id = extract_filename_info(notepath)
            m_date = m_date.strftime('%Y-%m-%d')
            if m_date >= date:
                note = parse_note(notepath) 
                for tag in note.tags:
                    self.index[tag].add(note_id)
        # Save the updated index:
        self.save_index()
Example #7
0
    def filter_notes(self, notepaths=[], criteria={}):
        """
        Given a list of filepaths of notes and a dictionary of criteria, onlu
        keep those notes that meet the criteria.

        NOTE: Filter notes based on days with filter_notes_by_date() because
        that is a lot faster.

        Parameters
        ----------
        notepaths : list
            A list of filepaths representing notes.
        criteria : dict
            A dictionary representing various criteria.

        Returns
        -------
        result : list
            A list of note that meet the criteria.

        """
        result = []
        N = len(notepaths)

        # NOTE: by default, the case of letters is ignored in title, body, and
        # tags. But this can be switched off as option:
        if criteria.get('ignore-case', True):
            if 'words' in criteria:
                criteria['words'] = [word.lower() for word in criteria['words']]
            if 'no-words' in criteria:
                criteria['no-words'] = [word.lower() for word in criteria['no-words']]
            if 'tags' in criteria:
                criteria['tags'] = [tag.lower() for tag in criteria['tags']]

        for i, notepath in enumerate(notepaths):
            self._print_progress_bar(i, N)
            note = parse_note(notepath)

            # most pattern matching is done to the whole content of a note,
            # regardless of whether it is title, body, or tags. So let's define
            # a variable for that:
            content = note.title + '\n' + note.body + '\n' + '#: ' + ' '.join(note.tags)

            tags = note.tags
            if criteria.get('ignore-case', True):
                content = content.lower()
                tags = [t.lower() for t in tags]

            # tags: if tags are given, at least one tag must appear
            if criteria.get('tags', []):
                if not set.intersection(set(criteria['tags']), set(tags)):
                    continue

            # words: all words must appear as a SUBSTRING
            # NOTE: this includes cases like 'string' in 'substring'
            # NOTE: matching is done in lower case
            if criteria.get('words', []):
                for word in criteria['words']:
                    if word not in content:
                        not_all_words_appear = True
                        break
                else:
                    not_all_words_appear = False
                if not_all_words_appear:
                    continue

            # no_words: none of these words must appear
            # NOTE: here only full words are considered. For example, 'substring'
            # does not count as an occurrence of 'string'.
            # NOTE: matching is done preserving the case of letters
            if criteria.get('no-words', []):
                if set.intersection(set(criteria['no-words']), set(content.split())):
                    continue

            result.append(notepath)
        return result
Example #8
0
    def display_note2(self, notepath):
        """
        Display the content of a note on the terminal.

        Using a bit of syntax here for highlighting:
        - if a line begins with "$:" or ends with ":$", the whole line is highlighted
        - if a line begins with "@:", the line is interpreted as a link to a
          reference
        - if a line begins with "http://" or "https://", the whole line is
          interpreted as a url
        - if a line begins with "#:", it is interpreted as a tag line
        - if a line contains text between two occurrences of ":::" (or whatever
          is defined a highlight_marker), that part is highlighted. If the line
          has an odd number of ":::", then the last remaining part of the line
          is highlighted.
        """
        with open(notepath, 'rt') as f:
            self.link_listing = {}

            note = parse_note(notepath)
            # title has been stripped, so we have to add a newline character
            # below.
            print_tokens([(Token.Title, note.title + '\n')], style=self.color_style)

            # # Make the body ends with a newline, if the body is nonempty:
            # if note.body and note.body[-1] != '\n':
            #     note.body += '\n'
            lines = note.body.split('\n')
            line_num = 0
            while line_num < len(lines):
                line = lines[line_num]

                # Is the line a link to a reference?
                if line.startswith('@:'):
                    ref = line[2:].strip()
                    index = len(self.link_listing) + 1
                    # NOTE: an extra newline is inserted below because it was
                    # stripped above
                    print_tokens([(Token.Link, str(index) + '  ' + ref + '\n')], style=self.color_style)
                    self.link_listing.append(os.path.join(self.refs, ref))
                    line_num += 1
                    continue

                # Is the line a link to a webpage?
                if line.startswith('http://') or line.startswith('https://'):
                    url = line.strip()
                    index = len(self.link_listing) + 1
                    # NOTE: an extra newline is inserted below because it was
                    # stripped above
                    print_tokens([(Token.Link, str(index) + '  ' + url + '\n')], style=self.color_style)
                    self.link_listing.append(url)
                    line_num += 1
                    continue

                # Does the line indicate a highlighted block?
                for i, marker in enumerate(self.highlight_markers):
                    if line == marker:
                        if i == 0:
                            token_type = Token.HL1
                        elif i == 1:
                            token_type = Token.HL2
                        else:  # i == 2
                            token_type = Token.HL3
                        line_num += 1
                        while line_num < len(lines) and lines[line_num] != marker:
                            print_tokens([(token_type, lines[line_num] + '\n')], style=self.color_style)
                            line_num += 1
                        # line_num += 1
                        continue

                # If neither of the above hold, the line is a regular line.
                i = 0
                marker_0_width = len(self.highlight_markers[0])
                marker_1_width = len(self.highlight_markers[1])
                while i < len(line):
                    if line[i:].startswith(self.highlight_markers[0]):
                        j = line[i + marker_0_width:].find(self.highlight_markers[0])
                        if j > -1:
                            print_tokens([(Token.Blue, line[i + marker_0_width: i + marker_0_width + j])], style=self.color_style)
                            i = i + marker_0_width + j + marker_0_width
                        else:
                            print_tokens([(Token.Blue, line[i + marker_0_width:])], style=self.color_style)
                            break
                    elif line[i:].startswith(self.highlight_markers[1]):
                        j = line[i + marker_1_width:].find(self.highlight_markers[1])
                        if j > -1:
                            print_tokens([(Token.Yellow, line[i + marker_1_width: i + marker_1_width + j])], style=self.color_style)
                            i = i + marker_1_width + j + marker_1_width
                        else:
                            print_tokens([(Token.Yellow, line[i + marker_1_width:])], style=self.color_style)
                            break
                    else:
                        print_tokens([(Token, line[i])], style=self.color_style)
                        i += 1
                # Add the newline that was lost when splitting the body on
                # \n.
                line_num += 1
                print()
            if note.tags:
                print_tokens([(Token.Tag, ', '.join(note.tags) + '\n')], style=self.color_style)
Example #9
0
    def tokenize(self, notepath):
        """
        Display the content of a note on the terminal.

        Using a bit of syntax here for highlighting:
        - if a line begins with "$:" or ends with ":$", the whole line is highlighted
        - if a line begins with "@:", the line is interpreted as a link to a
          reference
        - if a line begins with "http://" or "https://", the whole line is
          interpreted as a url
        - if a line begins with "#:", it is interpreted as a tag line
        - if a line contains text between two occurrences of ":::" (or whatever
          is defined a highlight_marker), that part is highlighted. If the line
          has an odd number of ":::", then the last remaining part of the line
          is highlighted.
        """
        with open(notepath, 'rt') as f:
            self.link_listing = {}

            note = parse_note(notepath)

            tokens = []

            tokens.append((Token.Tag, note.identifier))

            if note.title:
                tokens.append((Token.Punct, '\n'))
                tokens.append((Token.Title, note.title))

            if note.body:
                tokens.append((Token.Punct, '\n\n'))

                token_type = Token.Text
                i = 0

                while i < len(note.body):
                    if note.body[i:].startswith(self.highlight_markers[0]):
                        # toggle token_type on or off
                        token_type = Token.HL1 if token_type != Token.HL1 else Token.Text
                        t = len(self.highlight_markers[0])
                        i += t
                    elif note.body[i:].startswith(self.highlight_markers[1]):
                        token_type = Token.HL2 if token_type != Token.HL2 else Token.Text
                        t = len(self.highlight_markers[1])
                        i += t
                    elif note.body[i:].startswith(self.highlight_markers[2]):
                        token_type = Token.HL3 if token_type != Token.HL3 else Token.Text
                        t = len(self.highlight_markers[2])
                        i += t
                    else:
                        tokens.append((token_type, note.body[i]))
                        i += 1

            if note.links:
                tokens.append((Token.Punct, '\n\n'))
                for k, v in note.links:
                    tokens.append((Token.LinkID, '[{}] '.format(k)))
                    tokens.append((Token.Link, '{}'.format(v)))
                    tokens.append((Token.Punct, '\n'))
                    self.link_listing[k] = v
                # Delete the last newline character:
                del tokens[-1]

            if note.tags:
                if note.links:
                    tokens.append((Token.Punct, '\n'))
                else:
                    tokens.append((Token.Punct, '\n\n'))
                tokens.append((Token.Tag, ', '.join(note.tags)))

            tokens.append((Token.Punct, '\n'))
            return tokens