Esempio n. 1
0
func ExampleIsLetter() {
	fmt.Println(com.IsLetter('1'))
	fmt.Println(com.IsLetter('['))
	fmt.Println(com.IsLetter('a'))
	fmt.Println(com.IsLetter('Z'))
	// Output:
	// false
	// false
	// true
	// true
}
Esempio n. 2
0
func (r *Render) findType(name string) (*Link, bool) {
	if !com.IsLetter(name[0]) {
		return nil, false
	}

	// We cannot deal with struct field now.
	if name[len(name)-1] == '[' || name[len(name)-1] == ']' ||
		name[len(name)-1] == ' ' || name[len(name)-1] == ':' {
		return nil, false
	}

	// We cannot deal with chain operation.
	if name[0] == '.' {
		return nil, false
	}

	name = name[:len(name)-1]

	// This is for functions and types from imported packages.
	i := strings.Index(name, ".")
	// We cannot deal with struct field or chain operation now.
	if i != strings.LastIndex(name, ".") {
		return nil, false
	}

	if filte := r.FilteList[name]; filte {
		return nil, false
	}

	var left, right string
	if i > -1 {
		left = name[:i+1]
		right = name[i+1:]
	}

	for _, l := range r.Links {
		if i == -1 {
			// Exported types and functions in current package.
			if l.Name == name {
				return l, true
			}
		} else {
			// Functions and types from imported packages.
			if l.Name == left {
				if len(l.Path) > 0 {
					return &Link{Name: name, Path: "/" + l.Path + "#" + right}, true
				} else {
					return &Link{Name: name, Path: "#" + right}, true
				}
			} else if r.recv.name == left[:len(left)-1] {
				// fmt.Println(r.recv.tp + "." + right)
				// fmt.Println(r.findType(r.recv.tp + "." + right))
				return nil, false
			}
		}
	}

	r.FilteList[name] = true
	return nil, false
}
Esempio n. 3
0
// FormatCode highlights keywords and adds HTML links to them.
func FormatCode(w io.Writer, code *string, links []*Link) {
	length := len(*code) // Length of whole code.
	if length == 0 {
		return
	}

	*code = strings.Replace(*code, """, `"`, -1)
	*code = strings.Replace(*code, "'", `'`, -1)
	length = len(*code)

	strTag := uint8(0)      // Indicates what kind of string is chekcing.
	isString := false       // Indicates if right now is checking string.
	isComment := false      // Indicates if right now is checking comments.
	isBlockComment := false // Indicates if right now is checking block comments.
	last := 0               // Start index of the word.
	pos := 0                // Current index.

	for {
		// Cut words.
	CutWords:
		for {
			curChar := (*code)[pos] // Current check character.
			if !com.IsLetter(curChar) {
				if !isComment {
					switch {
					case curChar == '\'' || curChar == '"' || curChar == '`': // String.
						if !isString {
							// Set string tag.
							strTag = curChar
							isString = true
						} else {
							// CHeck if it is end of string or escaped character.
							if ((*code)[pos-1] == '\\' && (*code)[pos-2] == '\\') || (*code)[pos-1] != '\\' {
								// Check string tag.
								if curChar == strTag {
									// Handle string highlight.
									break CutWords
								}
							}
						}
					case !isString && curChar == '/' && ((*code)[pos+1] == '/' || (*code)[pos+1] == '*'):
						isComment = true
					case !isString && curChar > 47 && curChar < 58: // Ends with number.
					case !isString && curChar == '_' && (*code)[pos-1] != ' ': // Underline: _.
					case !isString && (curChar != '.' || curChar == '\n'):
						break CutWords
					}
				} else {
					if isBlockComment {
						// End of block comments.
						if curChar == '/' && (*code)[pos-1] == '*' {
							break CutWords
						}
					} else {
						switch {
						case curChar == '*' && (*code)[pos-1] == '/':
							// Start of block comments.
							isBlockComment = true
						case curChar == '\n':
							break CutWords
						}
					}
				}
			}

			if pos == length-1 {
				break CutWords
			}
			pos++
		}

		seg := (*code)[last : pos+1]
	CheckLink:
		switch {
		case isComment:
			isComment = false
			isBlockComment = false
			fmt.Fprintf(w, `<span class="com">%s</span>`, seg)
		case isString:
			isString = false
			fmt.Fprintf(w, `<span class="str">%s</span>`, template.HTMLEscapeString(seg))
		case seg == "\t":
			fmt.Fprintf(w, `%s`, "    ")
		case pos-last > 1:
			// Check if the last word of the paragraphy.
			l := len(seg)
			keyword := seg
			if !com.IsLetter(seg[l-1]) {
				keyword = seg[:l-1]
			} else {
				l++
			}

			// Check keywords.
			switch keyword {
			case "return", "break":
				fmt.Fprintf(w, `<span class="ret">%s</span>%s`, keyword, seg[l-1:])
				break CheckLink
			case "func", "range", "for", "if", "else", "type", "struct", "select", "case", "var", "const", "switch", "default", "continue":
				fmt.Fprintf(w, `<span class="key">%s</span>%s`, keyword, seg[l-1:])
				break CheckLink
			case "true", "false", "nil":
				fmt.Fprintf(w, `<span class="boo">%s</span>%s`, keyword, seg[l-1:])
				break CheckLink
			case "new", "append", "make", "panic", "recover", "len", "cap", "copy", "close", "delete", "defer":
				fmt.Fprintf(w, `<span class="bui">%s</span>%s`, keyword, seg[l-1:])
				break CheckLink
			}

			// Check links.
			link, ok := findType(seg[:l-1], links)
			if ok {
				switch {
				case len(link.Path) == 0 && len(link.Name) > 0:
					// Exported types in current package.
					fmt.Fprintf(w, `<a class="int" title="%s" href="#%s">%s</a>%s`,
						link.Comment, link.Name, link.Name, seg[l-1:])
				case len(link.Path) > 0 && len(link.Name) > 0:
					if strings.HasPrefix(link.Path, "#") {
						fmt.Fprintf(w, `<a class="ext" title="%s" href="%s">%s</a>%s`,
							link.Comment, link.Path, link.Name, seg[l-1:])
					} else {
						fmt.Fprintf(w, `<a class="ext" title="%s" target="_blank" href="%s">%s</a>%s`,
							link.Comment, link.Path, link.Name, seg[l-1:])
					}
				}
			} else if seg[len(seg)-1] == ' ' {
				fmt.Fprintf(w, "<span id=\"%s\">%s</span> ", seg[:len(seg)-1], seg[:len(seg)-1])
			} else {
				fmt.Fprintf(w, "%s", seg)
			}
		default:
			fmt.Fprintf(w, "%s", seg)
		}

		last = pos + 1
		pos++
		// End of code.
		if pos == length {
			fmt.Fprintf(w, "%s", (*code)[last:])
			return
		}
	}
}
Esempio n. 4
0
// Render highlights code.
func (r *Render) Render(name string, data []byte) []byte {
	if len(data) == 0 {
		return nil
	}

	code := string(data)
	l := len(code)

	buf := new(bytes.Buffer)
	//buf.WriteString("<pre>")

	strTag := uint8(0)
	isComment := false
	isBlockComment := false
	isString := false
	isFuncDecl := false
	isFuncBlock := false
	isHasRecv := false
	isTypeDecl := false
	last := 0
	pos := 0

	for {
	CutWords:
		for {
			curChar := code[pos]
			if !com.IsLetter(curChar) {
				if isComment {
					// Comment.
					if isBlockComment {
						// Check if in end of block comment.
						if curChar == '/' && code[pos-1] == '*' {
							break CutWords
						}
					} else {
						// Check if in start of block comment.
						if curChar == '*' && code[pos-1] == '/' {
							isBlockComment = true
						} else if curChar == '\n' {
							break CutWords
						}
					}
				} else {
					// String.
					if curChar == '\'' || curChar == '"' || curChar == '`' {
						if !isString {
							// Set string tag.
							strTag = curChar
							isString = true
						} else {
							// Check if it is end of string or escaped character.
							if (code[pos-1] == '\\' && code[pos-2] == '\\') || code[pos-1] != '\\' {
								// Check string tag.
								if curChar == strTag {
									// Handle string highlight.
									break CutWords
								}
							}
						}
					}

					if !isString {
						switch {
						case curChar == '/' && (code[pos+1] == '/' || code[pos+1] == '*'):
							isComment = true
						case curChar > 47 && curChar < 58: // Ends with number.
						case curChar == '_' && code[pos-1] != ' ': // Underline: _.
						case (curChar != '.' || curChar == '\n'):
							break CutWords
						}
					}
				}
			}

			if pos == l-1 {
				break CutWords
			}
			pos++
		}

		seg := code[last : pos+1]
	CheckLink:
		switch {
		case isComment:
			isComment = false
			isBlockComment = false
			fmt.Fprintf(buf, `<span class="com">%s</span>`, seg)
		case isString:
			isString = false
			fmt.Fprintf(buf, `<span class="str">%s</span>`, template.HTMLEscapeString(seg))
		case seg == "\t":
			fmt.Fprintf(buf, `%s`, "    ")
		case seg == "{":
			if isFuncDecl {
				isFuncDecl = false
				isFuncBlock = true
			}

			if isFuncBlock {
				r.blockLevel++
			}
			fmt.Fprintf(buf, "%s", seg)
		case seg == "}":
			if isFuncBlock {
				r.blockLevel--
			}
			if r.blockLevel == 0 {
				isFuncBlock = false
				r.recv.name = ""
			}
			fmt.Fprintf(buf, "%s", seg)
		case isFuncDecl:
			if isHasRecv {
				if seg != "(" && seg != " " && seg != "*" {
					if len(r.recv.name) == 0 {
						r.recv.name = seg[:len(seg)-1]
					} else {
						r.recv.tp = seg[:len(seg)-1]
						isHasRecv = false
					}
				}
			} else if len(seg) > 1 && code[pos] == '(' {
				if len(r.recv.name) > 0 {
					fmt.Fprintf(buf, "<span id=\"%s_%s\">%s</span>(", r.recv.tp, seg[:len(seg)-1], seg[:len(seg)-1])
				} else {
					fmt.Fprintf(buf, "<span id=\"%s\">%s</span>(", seg[:len(seg)-1], seg[:len(seg)-1])
				}
				break CheckLink
			}
			fallthrough
		case pos-last > 1:
			// Check if the last word of the paragraphy.
			l := len(seg)
			keyword := seg
			if !com.IsLetter(seg[l-1]) {
				keyword = seg[:l-1]
			} else {
				l++
			}

			// Check keywords.
			switch keyword {
			case "return", "break":
				fmt.Fprintf(buf, `<span class="ret">%s</span>%s`, keyword, seg[l-1:])
				break CheckLink
			case "func":
				isFuncDecl = true
				if code[pos+1] == '(' {
					isHasRecv = true
				}
				fallthrough
			case "package", "import", "range", "for", "if", "else", "type", "struct", "select", "case", "var", "const", "switch", "default", "continue":
				if keyword == "type" {
					isTypeDecl = true
				}
				fmt.Fprintf(buf, `<span class="key">%s</span>%s`, keyword, seg[l-1:])
				break CheckLink
			case "new", "append", "make", "panic", "recover", "len", "cap", "copy", "close", "delete", "defer":
				fmt.Fprintf(buf, `<span class="bui">%s</span>%s`, keyword, seg[l-1:])
				break CheckLink
			}

			if isPredeclared(keyword) {
				fmt.Fprintf(buf, `<span class="boo">%s</span>%s`, keyword, seg[l-1:])
				break CheckLink
			}

			// Check links.
			link, ok := r.findType(seg)
			if ok {
				switch {
				case strings.HasSuffix(link.Path, name) && len(link.Name) > 0: // Current file.
					fmt.Fprintf(buf, `<a class="int" title="%s" href="#%s">%s</a>%s`,
						link.Comment, link.Name, link.Name, seg[l-1:])
				case len(link.Path) > 0 && len(link.Name) > 0:
					if strings.HasPrefix(link.Path, "#") {
						fmt.Fprintf(buf, `<a class="ext" title="%s" href="%s">%s</a>%s`,
							link.Comment, link.Path, link.Name, seg[l-1:])
					} else {
						if strings.Index(link.Path, "#") > -1 {
							fmt.Fprintf(buf, `<a class="ext" title="%s" target="_blank" href="%s">%s</a>%s`,
								link.Comment, link.Path, link.Name, seg[l-1:])
						} else {
							fmt.Fprintf(buf, `<a class="ext" title="%s" target="_blank" href="/%s#%s">%s</a>%s`,
								link.Comment, link.Path, link.Name, link.Name, seg[l-1:])
						}
					}
				}
			} else if seg[len(seg)-1] == ' ' || seg[len(seg)-1] == '\n' {
				if isFuncDecl || isTypeDecl {
					isTypeDecl = false
					fmt.Fprintf(buf, "<span id=\"%s\">%s</span>%s", seg[:len(seg)-1], seg[:len(seg)-1], seg[l-1:])
				} else {
					fmt.Fprintf(buf, "%s", seg)
				}
			} else {
				fmt.Fprintf(buf, "%s", seg)
			}
		default:
			fmt.Fprintf(buf, "%s", seg)
		}

		last = pos + 1
		pos++
		// End of code.
		if pos == l {
			fmt.Fprintf(buf, "%s", code[last:])
			break
		}
	}

	return buf.Bytes()
}