Skip to content

Commit

Permalink
Implement tag and title search
Browse files Browse the repository at this point in the history
  • Loading branch information
Rokt33r committed Dec 22, 2020
1 parent c359ddd commit a3c0de4
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 23 deletions.
54 changes: 45 additions & 9 deletions src/components/molecules/SearchModalNoteResultItem.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback } from 'react'
import React, { useCallback, useMemo } from 'react'
import styled from '../../lib/styled'
import { NoteDoc } from '../../lib/db/types'
import Icon from '../atoms/Icon'
Expand All @@ -12,13 +12,16 @@ import {
getSearchResultKey,
MAX_SEARCH_PREVIEW_LINE_LENGTH,
SearchResult,
TagSearchResult,
} from '../../lib/search/search'
import { SearchMatchHighlight } from '../PreferencesModal/styled'
import { escapeRegExp } from '../../lib/string'
import cc from 'classcat'

interface SearchModalNoteResultItemProps {
note: NoteDoc
titleSearchResult: string | null
tagSearchResults: TagSearchResult[]
selectedItemId: string
searchResults: SearchResult[]
navigateToNote: (noteId: string) => void
Expand All @@ -32,6 +35,8 @@ interface SearchModalNoteResultItemProps {

const SearchModalNoteResultItem = ({
note,
titleSearchResult,
tagSearchResults,
searchResults,
navigateToNote,
selectedItemId,
Expand All @@ -42,7 +47,7 @@ const SearchModalNoteResultItem = ({
navigateToNote(note._id)
}, [navigateToNote, note._id])

const highlightMatchedTerm = useCallback((line, matchStr) => {
const highlightMatchedTerm = useCallback((line: string, matchStr: string) => {
const parts = line.split(new RegExp(`(${escapeRegExp(matchStr)})`, 'gi'))
return (
<span>
Expand All @@ -57,7 +62,7 @@ const SearchModalNoteResultItem = ({
)
}, [])
const beautifyPreviewLine = useCallback(
(line, matchStr) => {
(line: string, matchStr: string) => {
const multiline = matchStr.indexOf('\n') != -1
const beautifiedLine =
line.substring(0, MAX_SEARCH_PREVIEW_LINE_LENGTH) +
Expand Down Expand Up @@ -101,6 +106,13 @@ const SearchModalNoteResultItem = ({

const titleIsEmpty = note.title.trim().length === 0

const searchedTagNameMatchStringMap = useMemo(() => {
return tagSearchResults.reduce<Map<string, string>>((map, searchResult) => {
map.set(searchResult.tagName, searchResult.matchString)
return map
}, new Map())
}, [tagSearchResults])

return (
<Container>
<MetaContainer onClick={navigate}>
Expand All @@ -109,7 +121,11 @@ const SearchModalNoteResultItem = ({
<Icon path={mdiTextBoxOutline} />
</div>
<div className={cc(['title', titleIsEmpty && 'empty'])}>
{titleIsEmpty ? 'Untitled' : note.title}
{titleIsEmpty
? 'Untitled'
: titleSearchResult != null
? highlightMatchedTerm(note.title, titleSearchResult)
: note.title}
</div>
</div>
<div className='meta'>
Expand All @@ -120,7 +136,21 @@ const SearchModalNoteResultItem = ({
{note.tags.length > 0 && (
<div className='tags'>
<Icon className='icon' path={mdiTagMultiple} />{' '}
{note.tags.map((tag) => tag).join(', ')}
{note.tags.map((tag) => {
const matchedString = searchedTagNameMatchStringMap.get(tag)
if (matchedString == null) {
return (
<span className='tags__item' key={tag}>
{tag}
</span>
)
}
return (
<span className='tags__item' key={tag}>
{highlightMatchedTerm(tag, matchedString)}
</span>
)
})}
</div>
)}
</div>
Expand All @@ -140,18 +170,18 @@ const SearchModalNoteResultItem = ({
onDoubleClick={() =>
navigateToEditorFocused(
note._id,
result.lineNum - 1,
result.lineNumber - 1,
result.matchColumn
)
}
>
<SearchResultLeft title={result.lineStr}>
<SearchResultLeft title={result.lineString}>
<code>
{beautifyPreviewLine(result.lineStr, result.matchStr)}
{beautifyPreviewLine(result.lineString, result.matchString)}
</code>
</SearchResultLeft>
<SearchResultRight>
<code>{result.lineNum}</code>
<code>{result.lineNumber}</code>
</SearchResultRight>
</SearchResultItem>
))}
Expand Down Expand Up @@ -244,6 +274,12 @@ const MetaContainer = styled.div`
margin-right: 4px;
flex-shrink: 0;
}
& > .tags__item {
margin-right: 5px;
&:not(:last-child)::after {
content: ',';
}
}
}
}
&:last-child {
Expand Down
38 changes: 31 additions & 7 deletions src/components/organisms/SearchModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
SearchResult,
SEARCH_DEBOUNCE_TIMEOUT,
MERGE_SAME_LINE_RESULTS_INTO_ONE,
TagSearchResult,
} from '../../lib/search/search'
import CustomizedCodeEditor from '../atoms/CustomizedCodeEditor'
import CodeMirror from 'codemirror'
Expand Down Expand Up @@ -99,14 +100,35 @@ const SearchModal = ({ storage }: SearchModalProps) => {
return
}
const matchDataContent = getMatchData(note.content, regex)
// todo: [komediruzecki-04/12/2020] Use title and tag search to find those elements too, once found
// we can highlight them too
// const matchDataTitle = getMatchData(note.title, regex)
// const matchDataTags = getMatchData(note.tags.join(), regex)
if (matchDataContent && matchDataContent.length > 0) {

const titleMatchResult = note.title.match(regex)

const titleSearchResult =
titleMatchResult != null ? titleMatchResult[0] : null
const tagSearchResults = note.tags.reduce<TagSearchResult[]>(
(searchResults, tagName) => {
const matchResult = tagName.match(regex)
if (matchResult != null) {
searchResults.push({
tagName,
matchString: matchResult[0],
})
}
return searchResults
},
[]
)

if (
titleSearchResult ||
tagSearchResults.length > 0 ||
matchDataContent.length > 0
) {
const noteResultKey = excludeNoteIdPrefix(note._id)
noteToSearchResultMap[noteResultKey] = matchDataContent
searchResultData.push({
titleSearchResult,
tagSearchResults,
note: note,
results: matchDataContent,
})
Expand Down Expand Up @@ -201,7 +223,7 @@ const SearchModal = ({ storage }: SearchModalProps) => {
return
}
const focusLocation = {
line: searchResults[selectedIdx].lineNum - 1,
line: searchResults[selectedIdx].lineNumber - 1,
ch:
searchResults[selectedIdx].matchColumn +
searchResults[selectedIdx].matchLength,
Expand Down Expand Up @@ -236,7 +258,7 @@ const SearchModal = ({ storage }: SearchModalProps) => {
selectedItemId && !Number.isNaN(parseInt(selectedItemId))
? parseInt(selectedItemId)
: -1
addMarkers(codeMirror, searchResults[0].matchStr, selectedItemIdNum)
addMarkers(codeMirror, searchResults[0].matchString, selectedItemIdNum)
if (selectedItemIdNum != -1) {
focusEditorOnSelectedItem(codeMirror, searchResults, selectedItemIdNum)
}
Expand Down Expand Up @@ -288,6 +310,8 @@ const SearchModal = ({ storage }: SearchModalProps) => {
? selectedItemId
: '-1'
}
titleSearchResult={result.titleSearchResult}
tagSearchResults={result.tagSearchResults}
searchResults={result.results}
updateSelectedItem={updateSelectedItems}
navigateToNote={navigateToNote}
Expand Down
21 changes: 14 additions & 7 deletions src/lib/search/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,21 @@ import { EditorPosition } from '../CodeMirror'

export interface SearchResult {
id: string
lineStr: string
matchStr: string
lineString: string
matchString: string
matchColumn: number
matchLength: number
lineNum: number
lineNumber: number
}

export interface TagSearchResult {
tagName: string
matchString: string
}

export interface NoteSearchData {
titleSearchResult: string | null
tagSearchResults: TagSearchResult[]
results: SearchResult[]
note: NoteDoc
}
Expand Down Expand Up @@ -48,7 +55,7 @@ function getMatchDataFromGlobalColumn(
}
}

export function getMatchData(text: string, searchTerm: RegExp) {
export function getMatchData(text: string, searchTerm: RegExp): SearchResult[] {
const data: SearchResult[] = []

let resultId = 0
Expand All @@ -73,11 +80,11 @@ export function getMatchData(text: string, searchTerm: RegExp) {
}
data.push({
id: `${resultId++}`,
lineStr: lines[pos.line],
lineNum: pos.line + 1,
lineString: lines[pos.line],
lineNumber: pos.line + 1,
matchLength: matchStr.length,
matchColumn: pos.ch,
matchStr: matchStr,
matchString: matchStr,
})
}
return data
Expand Down

0 comments on commit a3c0de4

Please sign in to comment.