Closes #410 - adds ability to search by multiple criteria Adds ability to match case, match all, & use regexmain
@ -0,0 +1,4 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#fff" fill-opacity=".1" stroke="#C5C5C5" stroke-width=".5" d="M.25.25h15.5v15.5H.25z"/> | |||
<path fill="#C5C5C5" fill-rule="evenodd" d="M8 10.75c2.59 0 4.1-1.218 5.233-2.75C12.1 6.468 10.59 5.25 8 5.25S3.9 6.468 2.767 8C3.9 9.532 5.41 10.75 8 10.75zM14.75 8c-1.294 2-3.177 4-6.75 4s-5.456-2-6.75-4C2.544 6 4.427 4 8 4s5.456 2 6.75 4zM8 9.75a1.75 1.75 0 1 0 0-3.5 1.75 1.75 0 0 0 0 3.5z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,3 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#C5C5C5" fill-rule="evenodd" d="M8 10.75c2.59 0 4.1-1.218 5.233-2.75C12.1 6.468 10.59 5.25 8 5.25S3.9 6.468 2.767 8C3.9 9.532 5.41 10.75 8 10.75zM14.75 8c-1.294 2-3.177 4-6.75 4s-5.456-2-6.75-4C2.544 6 4.427 4 8 4s5.456 2 6.75 4zM8 9.75a1.75 1.75 0 1 0 0-3.5 1.75 1.75 0 0 0 0 3.5z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,4 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#fff" fill-opacity=".1" stroke="#C5C5C5" stroke-width=".5" d="M.25.25h15.5v15.5H.25z"/> | |||
<path fill="#C5C5C5" d="M5.811 4.914a1.748 1.748 0 0 0 .186.789c.065.128.148.26.248.395.1.131.22.27.36.418.227-.14.424-.27.59-.394.165-.124.302-.25.41-.377a1.248 1.248 0 0 0 .324-.855 1.01 1.01 0 0 0-.075-.395.909.909 0 0 0-.532-.52 1.143 1.143 0 0 0-.434-.078c-.332 0-.594.09-.787.27-.193.175-.29.424-.29.747zm.782 6.123c.223 0 .43-.022.619-.066a2.676 2.676 0 0 0 .978-.472c.139-.108.27-.223.393-.347l-2.24-2.434c-.2.132-.377.261-.532.389a2.244 2.244 0 0 0-.393.4 1.635 1.635 0 0 0-.237.473 1.912 1.912 0 0 0-.081.586c0 .215.032.415.098.598.07.18.168.335.295.467.127.127.284.227.469.299.185.071.395.107.63.107zM4 9.602c0-.311.039-.588.116-.831a2.27 2.27 0 0 1 .335-.664c.15-.2.332-.385.544-.556a7.35 7.35 0 0 1 .735-.508 13.39 13.39 0 0 1-.353-.443 3.563 3.563 0 0 1-.306-.49 3.282 3.282 0 0 1-.209-.557 2.438 2.438 0 0 1-.08-.64c0-.298.047-.565.144-.8.096-.24.235-.441.417-.605.18-.167.405-.293.67-.376.267-.088.57-.132.91-.132.32 0 .605.044.856.132a1.653 1.653 0 0 1 1.047.98c.093.236.14.503.14.802 0 .255-.049.492-.145.711a2.456 2.456 0 0 1-.388.604c-.162.184-.35.355-.561.515a9.266 9.266 0 0 1-.66.448l2.037 2.225a3.257 3.257 0 0 0 .503-.736c.066-.135.124-.281.174-.436.054-.156.1-.327.139-.515h1.065a5.77 5.77 0 0 1-.209.73 4.48 4.48 0 0 1-.272.622c-.1.195-.214.378-.341.55-.124.167-.26.333-.411.496L11.5 11.88h-1.302l-.972-1.028a7.43 7.43 0 0 1-.562.484c-.185.14-.382.26-.59.359A3.578 3.578 0 0 1 6.593 12a3.58 3.58 0 0 1-1.094-.155 2.271 2.271 0 0 1-.816-.467 2.11 2.11 0 0 1-.51-.753A2.817 2.817 0 0 1 4 9.602z"/> | |||
</svg> |
@ -0,0 +1,3 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#C5C5C5" d="M5.811 4.914a1.748 1.748 0 0 0 .186.789c.065.128.148.26.248.395.1.131.22.27.36.418.227-.14.424-.27.59-.394.165-.124.302-.25.41-.377a1.248 1.248 0 0 0 .324-.855 1.01 1.01 0 0 0-.075-.395.909.909 0 0 0-.532-.52 1.143 1.143 0 0 0-.434-.078c-.332 0-.594.09-.787.27-.193.175-.29.424-.29.747zm.782 6.123c.223 0 .43-.022.619-.066a2.676 2.676 0 0 0 .978-.472c.139-.108.27-.223.393-.347l-2.24-2.434c-.2.132-.377.261-.532.389a2.244 2.244 0 0 0-.393.4 1.635 1.635 0 0 0-.237.473 1.912 1.912 0 0 0-.081.586c0 .215.032.415.098.598.07.18.168.335.295.467.127.127.284.227.469.299.185.071.395.107.63.107zM4 9.602c0-.311.039-.588.116-.831a2.27 2.27 0 0 1 .335-.664c.15-.2.332-.385.544-.556a7.35 7.35 0 0 1 .735-.508 13.39 13.39 0 0 1-.353-.443 3.563 3.563 0 0 1-.306-.49 3.282 3.282 0 0 1-.209-.557 2.438 2.438 0 0 1-.08-.64c0-.298.047-.565.144-.8.096-.24.235-.441.417-.605.18-.167.405-.293.67-.376.267-.088.57-.132.91-.132.32 0 .605.044.856.132a1.653 1.653 0 0 1 1.047.98c.093.236.14.503.14.802 0 .255-.049.492-.145.711a2.456 2.456 0 0 1-.388.604c-.162.184-.35.355-.561.515a9.266 9.266 0 0 1-.66.448l2.037 2.225a3.257 3.257 0 0 0 .503-.736c.066-.135.124-.281.174-.436.054-.156.1-.327.139-.515h1.065a5.77 5.77 0 0 1-.209.73 4.48 4.48 0 0 1-.272.622c-.1.195-.214.378-.341.55-.124.167-.26.333-.411.496L11.5 11.88h-1.302l-.972-1.028a7.43 7.43 0 0 1-.562.484c-.185.14-.382.26-.59.359A3.578 3.578 0 0 1 6.593 12a3.58 3.58 0 0 1-1.094-.155 2.271 2.271 0 0 1-.816-.467 2.11 2.11 0 0 1-.51-.753A2.817 2.817 0 0 1 4 9.602z"/> | |||
</svg> |
@ -0,0 +1,4 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#fff" fill-opacity=".1" stroke="#C5C5C5" stroke-width=".5" d="M.25.25h15.5v15.5H.25z"/> | |||
<path fill="#C5C5C5" fill-rule="evenodd" d="M7.328 9.052l.864 2.35H9.25L6.108 3H5.12L2 11.402h1.062l.812-2.35h3.454zM5.695 4.453l.043.135 1.278 3.574h-2.83l1.268-3.574.043-.135.036-.156.031-.152.02-.126h.023l.023.126.028.152.037.156zm7.335 6.011v.936h.96V7.498c0-.719-.18-1.272-.539-1.661-.359-.389-.889-.583-1.588-.583-.199 0-.401.019-.606.056a4.875 4.875 0 0 0-1.078.326 2.081 2.081 0 0 0-.343.188v.984c.266-.23.566-.411.904-.54a2.927 2.927 0 0 1 1.052-.193c.188 0 .358.028.513.085a.98.98 0 0 1 .396.267c.109.121.193.279.252.472.059.193.088.427.088.7l-1.811.252c-.344.047-.64.126-.888.237a1.947 1.947 0 0 0-.615.419 1.6 1.6 0 0 0-.36.58 2.134 2.134 0 0 0-.117.721c0 .246.042.475.124.688.082.213.203.397.363.551.16.154.36.276.598.366.238.09.513.135.826.135.402 0 .76-.092 1.075-.278.315-.186.572-.454.771-.806h.023zm-2.128-1.743c.176-.064.401-.114.674-.149l1.465-.205v.609c0 .246-.041.475-.123.688a1.727 1.727 0 0 1-.343.557 1.573 1.573 0 0 1-.524.372 1.63 1.63 0 0 1-.668.135c-.187 0-.353-.025-.495-.076a1.03 1.03 0 0 1-.357-.211.896.896 0 0 1-.22-.316 1.005 1.005 0 0 1-.076-.393 1.6 1.6 0 0 1 .055-.44.739.739 0 0 1 .202-.334 1.16 1.16 0 0 1 .41-.237z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,3 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#C5C5C5" fill-rule="evenodd" d="M7.328 9.052l.864 2.35H9.25L6.108 3H5.12L2 11.402h1.062l.812-2.35h3.454zM5.695 4.453l.043.135 1.278 3.574h-2.83l1.268-3.574.043-.135.036-.156.031-.152.02-.126h.023l.023.126.028.152.037.156zm7.335 6.011v.936h.96V7.498c0-.719-.18-1.272-.539-1.661-.359-.389-.889-.583-1.588-.583-.199 0-.401.019-.606.056a4.875 4.875 0 0 0-1.078.326 2.081 2.081 0 0 0-.343.188v.984c.266-.23.566-.411.904-.54a2.927 2.927 0 0 1 1.052-.193c.188 0 .358.028.513.085a.98.98 0 0 1 .396.267c.109.121.193.279.252.472.059.193.088.427.088.7l-1.811.252c-.344.047-.64.126-.888.237a1.947 1.947 0 0 0-.615.419 1.6 1.6 0 0 0-.36.58 2.134 2.134 0 0 0-.117.721c0 .246.042.475.124.688.082.213.203.397.363.551.16.154.36.276.598.366.238.09.513.135.826.135.402 0 .76-.092 1.075-.278.315-.186.572-.454.771-.806h.023zm-2.128-1.743c.176-.064.401-.114.674-.149l1.465-.205v.609c0 .246-.041.475-.123.688a1.727 1.727 0 0 1-.343.557 1.573 1.573 0 0 1-.524.372 1.63 1.63 0 0 1-.668.135c-.187 0-.353-.025-.495-.076a1.03 1.03 0 0 1-.357-.211.896.896 0 0 1-.22-.316 1.005 1.005 0 0 1-.076-.393 1.6 1.6 0 0 1 .055-.44.739.739 0 0 1 .202-.334 1.16 1.16 0 0 1 .41-.237z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,4 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#fff" fill-opacity=".1" stroke="#C5C5C5" stroke-width=".5" d="M.25.25h15.5v15.5H.25z"/> | |||
<path fill="#C5C5C5" fill-rule="evenodd" d="M10.012 2h.976v3.113l2.56-1.557.486.885L11.47 6l2.564 1.559-.485.885-2.561-1.557V10h-.976V6.887l-2.56 1.557-.486-.885L9.53 6 6.966 4.441l.485-.885 2.561 1.557V2zM2 10h4v4H2v-4z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,3 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#C5C5C5" fill-rule="evenodd" d="M10.012 2h.976v3.113l2.56-1.557.486.885L11.47 6l2.564 1.559-.485.885-2.561-1.557V10h-.976V6.887l-2.56 1.557-.486-.885L9.53 6 6.966 4.441l.485-.885 2.561 1.557V2zM2 10h4v4H2v-4z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,4 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#000" fill-opacity=".1" stroke="#424242" stroke-width=".5" d="M.25.25h15.5v15.5H.25z"/> | |||
<path fill="#424242" fill-rule="evenodd" d="M8 10.75c2.59 0 4.1-1.218 5.233-2.75C12.1 6.468 10.59 5.25 8 5.25S3.9 6.468 2.767 8C3.9 9.532 5.41 10.75 8 10.75zM14.75 8c-1.294 2-3.177 4-6.75 4s-5.456-2-6.75-4C2.544 6 4.427 4 8 4s5.456 2 6.75 4zM8 9.75a1.75 1.75 0 1 0 0-3.5 1.75 1.75 0 0 0 0 3.5z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,3 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#424242" fill-rule="evenodd" d="M8 10.75c2.59 0 4.1-1.218 5.233-2.75C12.1 6.468 10.59 5.25 8 5.25S3.9 6.468 2.767 8C3.9 9.532 5.41 10.75 8 10.75zM14.75 8c-1.294 2-3.177 4-6.75 4s-5.456-2-6.75-4C2.544 6 4.427 4 8 4s5.456 2 6.75 4zM8 9.75a1.75 1.75 0 1 0 0-3.5 1.75 1.75 0 0 0 0 3.5z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,4 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#000" fill-opacity=".1" stroke="#424242" stroke-width=".5" d="M.25.25h15.5v15.5H.25z"/> | |||
<path fill="#424242" d="M5.811 4.914a1.748 1.748 0 0 0 .186.789c.065.128.148.26.248.395.1.131.22.27.36.418.227-.14.424-.27.59-.394.165-.124.302-.25.41-.377a1.248 1.248 0 0 0 .324-.855 1.01 1.01 0 0 0-.075-.395.909.909 0 0 0-.532-.52 1.143 1.143 0 0 0-.434-.078c-.332 0-.594.09-.787.27-.193.175-.29.424-.29.747zm.782 6.123c.223 0 .43-.022.619-.066a2.676 2.676 0 0 0 .978-.472c.139-.108.27-.223.393-.347l-2.24-2.434c-.2.132-.377.261-.532.389a2.244 2.244 0 0 0-.393.4 1.635 1.635 0 0 0-.237.473 1.912 1.912 0 0 0-.081.586c0 .215.032.415.098.598.07.18.168.335.295.467.127.127.284.227.469.299.185.071.395.107.63.107zM4 9.602c0-.311.039-.588.116-.831a2.27 2.27 0 0 1 .335-.664c.15-.2.332-.385.544-.556a7.35 7.35 0 0 1 .735-.508 13.39 13.39 0 0 1-.353-.443 3.563 3.563 0 0 1-.306-.49 3.282 3.282 0 0 1-.209-.557 2.438 2.438 0 0 1-.08-.64c0-.298.047-.565.144-.8.096-.24.235-.441.417-.605.18-.167.405-.293.67-.376.267-.088.57-.132.91-.132.32 0 .605.044.856.132a1.653 1.653 0 0 1 1.047.98c.093.236.14.503.14.802 0 .255-.049.492-.145.711a2.456 2.456 0 0 1-.388.604c-.162.184-.35.355-.561.515a9.266 9.266 0 0 1-.66.448l2.037 2.225a3.257 3.257 0 0 0 .503-.736c.066-.135.124-.281.174-.436.054-.156.1-.327.139-.515h1.065a5.77 5.77 0 0 1-.209.73 4.48 4.48 0 0 1-.272.622c-.1.195-.214.378-.341.55-.124.167-.26.333-.411.496L11.5 11.88h-1.302l-.972-1.028a7.43 7.43 0 0 1-.562.484c-.185.14-.382.26-.59.359A3.578 3.578 0 0 1 6.593 12a3.58 3.58 0 0 1-1.094-.155 2.271 2.271 0 0 1-.816-.467 2.11 2.11 0 0 1-.51-.753A2.817 2.817 0 0 1 4 9.602z"/> | |||
</svg> |
@ -0,0 +1,3 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#424242" d="M5.811 4.914a1.748 1.748 0 0 0 .186.789c.065.128.148.26.248.395.1.131.22.27.36.418.227-.14.424-.27.59-.394.165-.124.302-.25.41-.377a1.248 1.248 0 0 0 .324-.855 1.01 1.01 0 0 0-.075-.395.909.909 0 0 0-.532-.52 1.143 1.143 0 0 0-.434-.078c-.332 0-.594.09-.787.27-.193.175-.29.424-.29.747zm.782 6.123c.223 0 .43-.022.619-.066a2.676 2.676 0 0 0 .978-.472c.139-.108.27-.223.393-.347l-2.24-2.434c-.2.132-.377.261-.532.389a2.244 2.244 0 0 0-.393.4 1.635 1.635 0 0 0-.237.473 1.912 1.912 0 0 0-.081.586c0 .215.032.415.098.598.07.18.168.335.295.467.127.127.284.227.469.299.185.071.395.107.63.107zM4 9.602c0-.311.039-.588.116-.831a2.27 2.27 0 0 1 .335-.664c.15-.2.332-.385.544-.556a7.35 7.35 0 0 1 .735-.508 13.39 13.39 0 0 1-.353-.443 3.563 3.563 0 0 1-.306-.49 3.282 3.282 0 0 1-.209-.557 2.438 2.438 0 0 1-.08-.64c0-.298.047-.565.144-.8.096-.24.235-.441.417-.605.18-.167.405-.293.67-.376.267-.088.57-.132.91-.132.32 0 .605.044.856.132a1.653 1.653 0 0 1 1.047.98c.093.236.14.503.14.802 0 .255-.049.492-.145.711a2.456 2.456 0 0 1-.388.604c-.162.184-.35.355-.561.515a9.266 9.266 0 0 1-.66.448l2.037 2.225a3.257 3.257 0 0 0 .503-.736c.066-.135.124-.281.174-.436.054-.156.1-.327.139-.515h1.065a5.77 5.77 0 0 1-.209.73 4.48 4.48 0 0 1-.272.622c-.1.195-.214.378-.341.55-.124.167-.26.333-.411.496L11.5 11.88h-1.302l-.972-1.028a7.43 7.43 0 0 1-.562.484c-.185.14-.382.26-.59.359A3.578 3.578 0 0 1 6.593 12a3.58 3.58 0 0 1-1.094-.155 2.271 2.271 0 0 1-.816-.467 2.11 2.11 0 0 1-.51-.753A2.817 2.817 0 0 1 4 9.602z"/> | |||
</svg> |
@ -0,0 +1,4 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#000" fill-opacity=".1" stroke="#424242" stroke-width=".5" d="M.25.25h15.5v15.5H.25z"/> | |||
<path fill="#424242" fill-rule="evenodd" d="M7.328 9.052l.864 2.35H9.25L6.108 3H5.12L2 11.402h1.062l.812-2.35h3.454zM5.695 4.453l.043.135 1.278 3.574h-2.83l1.268-3.574.043-.135.036-.156.031-.152.02-.126h.023l.023.126.028.152.037.156zm7.335 6.011v.936h.96V7.498c0-.719-.18-1.272-.539-1.661-.359-.389-.889-.583-1.588-.583-.199 0-.401.019-.606.056a4.875 4.875 0 0 0-1.078.326 2.081 2.081 0 0 0-.343.188v.984c.266-.23.566-.411.904-.54a2.927 2.927 0 0 1 1.052-.193c.188 0 .358.028.513.085a.98.98 0 0 1 .396.267c.109.121.193.279.252.472.059.193.088.427.088.7l-1.811.252c-.344.047-.64.126-.888.237a1.947 1.947 0 0 0-.615.419 1.6 1.6 0 0 0-.36.58 2.134 2.134 0 0 0-.117.721c0 .246.042.475.124.688.082.213.203.397.363.551.16.154.36.276.598.366.238.09.513.135.826.135.402 0 .76-.092 1.075-.278.315-.186.572-.454.771-.806h.023zm-2.128-1.743c.176-.064.401-.114.674-.149l1.465-.205v.609c0 .246-.041.475-.123.688a1.727 1.727 0 0 1-.343.557 1.573 1.573 0 0 1-.524.372 1.63 1.63 0 0 1-.668.135c-.187 0-.353-.025-.495-.076a1.03 1.03 0 0 1-.357-.211.896.896 0 0 1-.22-.316 1.005 1.005 0 0 1-.076-.393 1.6 1.6 0 0 1 .055-.44.739.739 0 0 1 .202-.334 1.16 1.16 0 0 1 .41-.237z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,3 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#424242" fill-rule="evenodd" d="M7.328 9.052l.864 2.35H9.25L6.108 3H5.12L2 11.402h1.062l.812-2.35h3.454zM5.695 4.453l.043.135 1.278 3.574h-2.83l1.268-3.574.043-.135.036-.156.031-.152.02-.126h.023l.023.126.028.152.037.156zm7.335 6.011v.936h.96V7.498c0-.719-.18-1.272-.539-1.661-.359-.389-.889-.583-1.588-.583-.199 0-.401.019-.606.056a4.875 4.875 0 0 0-1.078.326 2.081 2.081 0 0 0-.343.188v.984c.266-.23.566-.411.904-.54a2.927 2.927 0 0 1 1.052-.193c.188 0 .358.028.513.085a.98.98 0 0 1 .396.267c.109.121.193.279.252.472.059.193.088.427.088.7l-1.811.252c-.344.047-.64.126-.888.237a1.947 1.947 0 0 0-.615.419 1.6 1.6 0 0 0-.36.58 2.134 2.134 0 0 0-.117.721c0 .246.042.475.124.688.082.213.203.397.363.551.16.154.36.276.598.366.238.09.513.135.826.135.402 0 .76-.092 1.075-.278.315-.186.572-.454.771-.806h.023zm-2.128-1.743c.176-.064.401-.114.674-.149l1.465-.205v.609c0 .246-.041.475-.123.688a1.727 1.727 0 0 1-.343.557 1.573 1.573 0 0 1-.524.372 1.63 1.63 0 0 1-.668.135c-.187 0-.353-.025-.495-.076a1.03 1.03 0 0 1-.357-.211.896.896 0 0 1-.22-.316 1.005 1.005 0 0 1-.076-.393 1.6 1.6 0 0 1 .055-.44.739.739 0 0 1 .202-.334 1.16 1.16 0 0 1 .41-.237z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,4 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#000" fill-opacity=".1" stroke="#424242" stroke-width=".5" d="M.25.25h15.5v15.5H.25z"/> | |||
<path fill="#424242" fill-rule="evenodd" d="M10.012 2h.976v3.113l2.56-1.557.486.885L11.47 6l2.564 1.559-.485.885-2.561-1.557V10h-.976V6.887l-2.56 1.557-.486-.885L9.53 6 6.966 4.441l.485-.885 2.561 1.557V2zM2 10h4v4H2v-4z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,3 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"> | |||
<path fill="#424242" fill-rule="evenodd" d="M10.012 2h.976v3.113l2.56-1.557.486.885L11.47 6l2.564 1.559-.485.885-2.561-1.557V10h-.976V6.887l-2.56 1.557-.486-.885L9.53 6 6.966 4.441l.485-.885 2.561 1.557V2zM2 10h4v4H2v-4z" clip-rule="evenodd"/> | |||
</svg> |
@ -0,0 +1,497 @@ | |||
'use strict'; | |||
/* eslint-disable no-loop-func */ | |||
import { QuickInputButton } from 'vscode'; | |||
import { Container } from '../../container'; | |||
import { GitLogCommit, GitService, Repository } from '../../git/gitService'; | |||
import { GlyphChars } from '../../constants'; | |||
import { QuickCommandBase, StepAsyncGenerator, StepSelection, StepState } from '../quickCommand'; | |||
import { RepositoryQuickPickItem } from '../../quickpicks'; | |||
import { Iterables, Mutable, Strings } from '../../system'; | |||
import { Logger } from '../../logger'; | |||
import { | |||
CommitQuickPickItem, | |||
Directive, | |||
DirectiveQuickPickItem, | |||
QuickPickItemOfT | |||
} from '../../quickpicks/gitQuickPicks'; | |||
interface State { | |||
repo: Repository; | |||
search: string; | |||
matchAll: boolean; | |||
matchCase: boolean; | |||
matchRegex: boolean; | |||
showInView: boolean; | |||
} | |||
export interface SearchGitCommandArgs { | |||
readonly command: 'search'; | |||
state?: Partial<State>; | |||
confirm?: boolean; | |||
prefillOnly?: boolean; | |||
} | |||
const searchOperators = new Set<string>(['', 'author:', 'change:', 'commit:', 'file:']); | |||
const searchOperatorToTitleMap = new Map<string, string>([ | |||
['', 'Search by Message'], | |||
['author:', 'Search by Author or Committer'], | |||
['change:', 'Search by Changes'], | |||
['commit:', 'Search by Commit ID'], | |||
['file:', 'Search by File'] | |||
]); | |||
export class SearchGitCommand extends QuickCommandBase<State> { | |||
constructor(args?: SearchGitCommandArgs) { | |||
super('search', 'search', 'Search', { | |||
description: 'aka grep, searches for commits' | |||
}); | |||
if (args == null || args.state === undefined) return; | |||
let counter = 0; | |||
if (args.state.repo !== undefined) { | |||
counter++; | |||
} | |||
if (args.state.search !== undefined && !args.prefillOnly) { | |||
counter++; | |||
} | |||
this._initialState = { | |||
counter: counter, | |||
confirm: args.confirm, | |||
...args.state | |||
}; | |||
} | |||
get canConfirm(): boolean { | |||
return false; | |||
} | |||
isMatch(name: string) { | |||
return super.isMatch(name) || name === 'grep'; | |||
} | |||
protected async *steps(): StepAsyncGenerator { | |||
const state: StepState<State> = this._initialState === undefined ? { counter: 0 } : this._initialState; | |||
let oneRepo = false; | |||
let pickedCommit: GitLogCommit | undefined; | |||
const cfg = Container.config.gitCommands.search; | |||
if (state.matchAll === undefined) { | |||
state.matchAll = cfg.matchAll; | |||
} | |||
if (state.matchCase === undefined) { | |||
state.matchCase = cfg.matchCase; | |||
} | |||
if (state.matchRegex === undefined) { | |||
state.matchRegex = cfg.matchRegex; | |||
} | |||
if (state.showInView === undefined) { | |||
state.showInView = cfg.showInView; | |||
} | |||
while (true) { | |||
try { | |||
if (state.repo === undefined || state.counter < 1) { | |||
const repos = [...(await Container.git.getOrderedRepositories())]; | |||
if (repos.length === 1) { | |||
oneRepo = true; | |||
state.counter++; | |||
state.repo = repos[0]; | |||
} else { | |||
const active = state.repo ? state.repo : await Container.git.getActiveRepository(); | |||
const step = this.createPickStep<RepositoryQuickPickItem>({ | |||
multiselect: true, | |||
title: this.title, | |||
placeholder: 'Choose repositories', | |||
items: await Promise.all( | |||
repos.map(r => | |||
RepositoryQuickPickItem.create(r, r.id === (active && active.id), { | |||
branch: true, | |||
fetched: true, | |||
status: true | |||
}) | |||
) | |||
) | |||
}); | |||
const selection: StepSelection<typeof step> = yield step; | |||
if (!this.canPickStepMoveNext(step, state, selection)) { | |||
break; | |||
} | |||
state.repo = selection[0].item; | |||
} | |||
} | |||
if (state.search === undefined || state.counter < 2) { | |||
const items: QuickPickItemOfT<string>[] = [ | |||
{ | |||
label: `${this.title} by Message`, | |||
description: `pattern ${GlyphChars.Dash} use quotes to search for phrases`, | |||
item: '' | |||
}, | |||
{ | |||
label: `${this.title} by Author or Committer`, | |||
description: 'author: pattern', | |||
item: 'author:' | |||
}, | |||
{ | |||
label: `${this.title} by Commit ID`, | |||
description: 'commit: sha', | |||
item: 'commit:' | |||
}, | |||
{ | |||
label: `${this.title} by Files`, | |||
description: 'file: glob', | |||
item: 'file:' | |||
}, | |||
{ | |||
label: `${this.title} by Changes`, | |||
description: 'change: pattern', | |||
item: 'change:' | |||
} | |||
]; | |||
const titleSuffix = `${Strings.pad(GlyphChars.Dot, 2, 2)}${state.repo.formattedName}`; | |||
const matchCaseButton: Mutable<QuickInputButton> = { | |||
iconPath: state.matchCase | |||
? { | |||
dark: Container.context.asAbsolutePath( | |||
'images/dark/icon-match-case-selected.svg' | |||
) as any, | |||
light: Container.context.asAbsolutePath( | |||
'images/light/icon-match-case-selected.svg' | |||
) as any | |||
} | |||
: { | |||
dark: Container.context.asAbsolutePath('images/dark/icon-match-case.svg') as any, | |||
light: Container.context.asAbsolutePath('images/light/icon-match-case.svg') as any | |||
}, | |||
tooltip: 'Match Case' | |||
}; | |||
const matchAllButton: Mutable<QuickInputButton> = { | |||
iconPath: state.matchAll | |||
? { | |||
dark: Container.context.asAbsolutePath( | |||
'images/dark/icon-match-all-selected.svg' | |||
) as any, | |||
light: Container.context.asAbsolutePath( | |||
'images/light/icon-match-all-selected.svg' | |||
) as any | |||
} | |||
: { | |||
dark: Container.context.asAbsolutePath('images/dark/icon-match-all.svg') as any, | |||
light: Container.context.asAbsolutePath('images/light/icon-match-all.svg') as any | |||
}, | |||
tooltip: 'Match All' | |||
}; | |||
const matchRegexButton: Mutable<QuickInputButton> = { | |||
iconPath: state.matchRegex | |||
? { | |||
dark: Container.context.asAbsolutePath( | |||
'images/dark/icon-match-regex-selected.svg' | |||
) as any, | |||
light: Container.context.asAbsolutePath( | |||
'images/light/icon-match-regex-selected.svg' | |||
) as any | |||
} | |||
: { | |||
dark: Container.context.asAbsolutePath('images/dark/icon-match-regex.svg') as any, | |||
light: Container.context.asAbsolutePath('images/light/icon-match-regex.svg') as any | |||
}, | |||
tooltip: 'Match using Regular Expressions' | |||
}; | |||
const showInViewButton: Mutable<QuickInputButton> = { | |||
iconPath: state.showInView | |||
? { | |||
dark: Container.context.asAbsolutePath('images/dark/icon-eye-selected.svg') as any, | |||
light: Container.context.asAbsolutePath('images/light/icon-eye-selected.svg') as any | |||
} | |||
: { | |||
dark: Container.context.asAbsolutePath('images/dark/icon-eye.svg') as any, | |||
light: Container.context.asAbsolutePath('images/light/icon-eye.svg') as any | |||
}, | |||
tooltip: 'Show Results in the Search Commits View' | |||
}; | |||
const step = this.createPickStep<QuickPickItemOfT<string>>({ | |||
title: `${this.title}${titleSuffix}`, | |||
placeholder: 'e.g. "Updates dependencies" author:eamodio', | |||
matchOnDescription: true, | |||
matchOnDetail: true, | |||
additionalButtons: [matchCaseButton, matchAllButton, matchRegexButton, showInViewButton], | |||
items: items, | |||
value: state.search, | |||
onDidAccept: (quickpick): boolean => { | |||
const pick = quickpick.selectedItems[0]; | |||
if (!searchOperators.has(pick.item)) return true; | |||
const value = quickpick.value.trim(); | |||
if (value.length === 0 || searchOperators.has(value)) { | |||
quickpick.value = pick.item; | |||
} else { | |||
quickpick.value = `${value} ${pick.item}`; | |||
} | |||
void step.onDidChangeValue!(quickpick); | |||
return false; | |||
}, | |||
onDidClickButton: (quickpick, button) => { | |||
if (button === matchCaseButton) { | |||
state.matchCase = !state.matchCase; | |||
matchCaseButton.iconPath = state.matchCase | |||
? { | |||
dark: Container.context.asAbsolutePath( | |||
'images/dark/icon-match-case-selected.svg' | |||
) as any, | |||
light: Container.context.asAbsolutePath( | |||
'images/light/icon-match-case-selected.svg' | |||
) as any | |||
} | |||
: { | |||
dark: Container.context.asAbsolutePath( | |||
'images/dark/icon-match-case.svg' | |||
) as any, | |||
light: Container.context.asAbsolutePath( | |||
'images/light/icon-match-case.svg' | |||
) as any | |||
}; | |||
return; | |||
} | |||
if (button === matchAllButton) { | |||
state.matchAll = !state.matchAll; | |||
matchAllButton.iconPath = state.matchAll | |||
? { | |||
dark: Container.context.asAbsolutePath( | |||
'images/dark/icon-match-all-selected.svg' | |||
) as any, | |||
light: Container.context.asAbsolutePath( | |||
'images/light/icon-match-all-selected.svg' | |||
) as any | |||
} | |||
: { | |||
dark: Container.context.asAbsolutePath( | |||
'images/dark/icon-match-all.svg' | |||
) as any, | |||
light: Container.context.asAbsolutePath( | |||
'images/light/icon-match-all.svg' | |||
) as any | |||
}; | |||
return; | |||
} | |||
if (button === matchRegexButton) { | |||
state.matchRegex = !state.matchRegex; | |||
matchRegexButton.iconPath = state.matchRegex | |||
? { | |||
dark: Container.context.asAbsolutePath( | |||
'images/dark/icon-match-regex-selected.svg' | |||
) as any, | |||
light: Container.context.asAbsolutePath( | |||
'images/light/icon-match-regex-selected.svg' | |||
) as any | |||
} | |||
: { | |||
dark: Container.context.asAbsolutePath( | |||
'images/dark/icon-match-regex.svg' | |||
) as any, | |||
light: Container.context.asAbsolutePath( | |||
'images/light/icon-match-regex.svg' | |||
) as any | |||
}; | |||
return; | |||
} | |||
if (button === showInViewButton) { | |||
state.showInView = !state.showInView; | |||
showInViewButton.iconPath = state.showInView | |||
? { | |||
dark: Container.context.asAbsolutePath( | |||
'images/dark/icon-eye-selected.svg' | |||
) as any, | |||
light: Container.context.asAbsolutePath( | |||
'images/light/icon-eye-selected.svg' | |||
) as any | |||
} | |||
: { | |||
dark: Container.context.asAbsolutePath('images/dark/icon-eye.svg') as any, | |||
light: Container.context.asAbsolutePath('images/light/icon-eye.svg') as any | |||
}; | |||
} | |||
}, | |||
onDidChangeValue: (quickpick): boolean => { | |||
const operations = GitService.parseSearchOperations(quickpick.value.trim()); | |||
quickpick.title = | |||
operations.size === 0 || operations.size > 1 | |||
? `${this.title}${titleSuffix}` | |||
: `${searchOperatorToTitleMap.get(operations.keys().next().value)!}${titleSuffix}`; | |||
if (quickpick.value.length === 0) { | |||
quickpick.items = items; | |||
} else { | |||
quickpick.items = [ | |||
{ | |||
label: 'Search for commits matching', | |||
description: quickpick.value, | |||
item: quickpick.value | |||
} | |||
]; | |||
} | |||
return true; | |||
} | |||
}); | |||
const selection: StepSelection<typeof step> = yield step; | |||
if (!this.canPickStepMoveNext(step, state, selection)) { | |||
if (oneRepo) { | |||
break; | |||
} | |||
continue; | |||
} | |||
state.search = selection[0].item.trim(); | |||
} | |||
const resultsPromise = Container.git.getLogForSearch(state.repo.path, { | |||
pattern: state.search, | |||
matchAll: state.matchAll, | |||
matchCase: state.matchCase, | |||
matchRegex: state.matchRegex | |||
}); | |||
if (state.showInView) { | |||
void Container.searchView.search( | |||
state.repo.path, | |||
{ | |||
pattern: state.search, | |||
matchAll: state.matchAll, | |||
matchCase: state.matchCase, | |||
matchRegex: state.matchRegex | |||
}, | |||
{ | |||
label: { label: `commits matching: ${state.search}` } | |||
}, | |||
resultsPromise | |||
); | |||
break; | |||
} | |||
const results = await resultsPromise; | |||
const openInViewButton: QuickInputButton = { | |||
iconPath: { | |||
dark: Container.context.asAbsolutePath('images/dark/icon-link.svg') as any, | |||
light: Container.context.asAbsolutePath('images/light/icon-link.svg') as any | |||
}, | |||
tooltip: 'Open Results in the Search Commits View' | |||
}; | |||
const step = this.createPickStep<CommitQuickPickItem>({ | |||
title: `${this.title}${Strings.pad(GlyphChars.Dot, 2, 2)}${state.repo.formattedName}`, | |||
placeholder: | |||
results === undefined | |||
? `No results for commits matching: ${state.search}` | |||
: `${Strings.pluralize('result', results.count, { | |||
number: results.truncated ? `${results.count}+` : undefined | |||
})} for commits matching: ${state.search}`, | |||
matchOnDescription: true, | |||
matchOnDetail: true, | |||
items: | |||
results === undefined | |||
? [ | |||
DirectiveQuickPickItem.create(Directive.Back, true), | |||
DirectiveQuickPickItem.create(Directive.Cancel) | |||
] | |||
: [ | |||
...Iterables.map(results.commits.values(), commit => | |||
CommitQuickPickItem.create( | |||
commit, | |||
commit.ref === (pickedCommit && pickedCommit.ref), | |||
{ compact: true, icon: true } | |||
) | |||
) | |||
], | |||
additionalButtons: [openInViewButton], | |||
onDidClickButton: (quickpick, button) => { | |||
if (button !== openInViewButton) return; | |||
void Container.searchView.search( | |||
state.repo!.path, | |||
{ | |||
pattern: state.search!, | |||
matchAll: state.matchAll, | |||
matchCase: state.matchCase, | |||
matchRegex: state.matchRegex | |||
}, | |||
{ | |||
label: { label: `commits matching: ${state.search}` } | |||
}, | |||
results | |||
); | |||
} | |||
}); | |||
const selection: StepSelection<typeof step> = yield step; | |||
if (!this.canPickStepMoveNext(step, state, selection)) { | |||
continue; | |||
} | |||
state.counter--; | |||
pickedCommit = selection[0].item; | |||
void Container.searchView.search( | |||
pickedCommit.repoPath, | |||
{ pattern: `commit:${pickedCommit.sha}` }, | |||
{ | |||
label: { label: `commits matching: commit:${pickedCommit.shortSha}` } | |||
} | |||
); | |||
// const gitCommandArgs: GitCommandsCommandArgs = { | |||
// command: 'search', | |||
// state: { ...state } | |||
// }; | |||
// const commandArgs: ShowQuickCommitDetailsCommandArgs = { | |||
// sha: commit.sha, | |||
// commit: commit, | |||
// goBackCommand: new CommandQuickPickItem( | |||
// { | |||
// label: 'Back', | |||
// description: '' | |||
// }, | |||
// Commands.GitCommands, | |||
// [gitCommandArgs] | |||
// ) | |||
// }; | |||
// void commands.executeCommand(Commands.ShowQuickCommitDetails, commit.toGitUri(), commandArgs); | |||
// break; | |||
} catch (ex) { | |||
Logger.error(ex, this.title); | |||
throw ex; | |||
} | |||
} | |||
return undefined; | |||
} | |||
} |