aboutsummaryrefslogtreecommitdiff
path: root/ui/messages/parser/htmltagarray.go
blob: d66d7d9d5bb1e8bbdc3364c088f670c1658ebc64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// gomuks - A terminal Matrix client written in Go.
// Copyright (C) 2018 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package parser

// TagWithMeta is an open HTML tag with some metadata (e.g. list index, a href value).
type TagWithMeta struct {
	Tag     string
	Counter int
	Meta    string
	Text    string
}

// BlankTag is a blank TagWithMeta object.
var BlankTag = &TagWithMeta{}

// TagArray is a reversed queue for remembering what HTML tags are open.
type TagArray []*TagWithMeta

// Push adds the given tag to the array.
func (ta *TagArray) Push(tag string) {
	ta.PushMeta(&TagWithMeta{Tag: tag})
}

// Push adds the given tag to the array.
func (ta *TagArray) PushMeta(tag *TagWithMeta) {
	*ta = append(*ta, BlankTag)
	copy((*ta)[1:], *ta)
	(*ta)[0] = tag
}

// Pop removes the given tag from the array.
func (ta *TagArray) Pop(tag string) (removed *TagWithMeta) {
	if len(*ta) == 0 {
		return
	} else if (*ta)[0].Tag == tag {
		// This is the default case and is lighter than append(), so we handle it separately.
		removed = (*ta)[0]
		*ta = (*ta)[1:]
	} else if index := ta.Index(tag); index != -1 {
		removed = (*ta)[index]
		*ta = append((*ta)[:index], (*ta)[index+1:]...)
	}
	return
}

// Index returns the first index where the given tag is, or -1 if it's not in the list.
func (ta *TagArray) Index(tag string) int {
	return ta.IndexAfter(tag, -1)
}

// IndexAfter returns the first index after the given index where the given tag is,
// or -1 if the given tag is not on the list after the given index.
func (ta *TagArray) IndexAfter(tag string, after int) int {
	for i := after + 1; i < len(*ta); i++ {
		if (*ta)[i].Tag == tag {
			return i
		}
	}
	return -1
}

// Get returns the first occurrence of the given tag, or nil if it's not in the list.
func (ta *TagArray) Get(tag string) *TagWithMeta {
	return ta.GetAfter(tag, -1)
}

// IndexAfter returns the first occurrence of the given tag, or nil if the given
// tag is not on the list after the given index.
func (ta *TagArray) GetAfter(tag string, after int) *TagWithMeta {
	for i := after + 1; i < len(*ta); i++ {
		if (*ta)[i].Tag == tag {
			return (*ta)[i]
		}
	}
	return nil
}

// Has returns whether or not the list has at least one of the given tags.
func (ta *TagArray) Has(tags ...string) bool {
	for _, tag := range tags {
		if index := ta.Index(tag); index != -1 {
			return true
		}
	}
	return false
}